How to implement lazy loading in Java
Lazy loading is a common optimization technique that delays the creation or initialization of an object until it is first used. This technology can help us reduce the waste of resources and improve the operating efficiency of the program.
In Scala, we can use the keyword lazy to define lazy variables and implement lazy loading (lazy loading). But in Java, we need to use other techniques to achieve lazy loading. In this article, we will describe how to use the Supplier interface in Java and the double-checked locking pattern to implement lazy loading and guarantee only one initialization.
Use the Supplier interface to implement lazy loading
The Supplier interface in Java is a functional interface for providing objects of type T. We can implement lazy loading by passing a lambda expression to an instance of the Supplier interface.
The following is a sample code for lazy loading using the Supplier interface:
javaCopy code import java.util.function.Supplier; publicclassLazy<T> { private final Supplier<T> supplier; private T value; public Lazy(Supplier<T> supplier) { this.supplier = supplier; } public T get() { if (value == null) { value = supplier. get(); } return value; } } Copy Code
In the above code, we define a generic class Lazy
Here is sample code using the Lazy class:
javaCopy code publicclassLazyDemo { publicstatic void main(String[] args) { Lazy<String> lazyString = new Lazy<>(() -> { System.out.println("Initializing lazy string..."); return"Hello, World!"; }); System.out.println(lazyString.get()); System.out.println(lazyString.get()); System.out.println(lazyString.get()); } }
In the above code, we create a Lazy
Lazy loading with double-checked locking
The double-checked locking pattern is a common technique used to implement lazy loading. It utilizes synchronized blocks and the volatile keyword to ensure thread safety and lazy loading.
The following is lazy loading using the double-checked locking pattern
The first step is to create a Java class and declare a generic type to store the lazy calculated value. In our example, we will use the generic type T so that we can use the Lazy class to store any type of value.
javaCopy code public class Lazy<T> { private final Supplier<T> supplier; private volatile T result; public Lazy(Supplier<T> supplier) { this.supplier = supplier; } public T get() { T value = result; if (value == null) { synchronized (this) { value = result; if (value == null) { value = supplier. get(); result = value; } } } return value; } }
In the above code, we declare a member variable supplier of private Supplier type, which passes the function to calculate the value as a parameter. We also declare a volatile member variable result, which is used to store the calculation result and ensure correct use in a multi-threaded environment.
The second step is to implement the logic of lazy loading. In our Lazy class, we implement a get() method that returns the result of the computation. In the get() method, we use a double-check locking mechanism to ensure the correctness of lazy loading. On the first call to the get() method, we check if the result variable is empty. If empty, we use a synchronized code block to avoid multiple threads computing values at the same time. In the synchronized code block, we check again that the result variable is not empty, to ensure that another thread has not calculated a value while locking. If it is empty, we call the supplier.get() method to calculate the value and store the result in the result variable. After the calculation is complete, we return the value to the caller.
The third step is to use the singleton pattern to ensure that it is only initialized once. To ensure that it is only initialized once, we declare the result variable as volatile and use a double-checked locking mechanism. In the process of computing a value, if another thread has already computed a value, the previously computed result is returned.
Step four, test that our Lazy class works as expected. In the test, we will create a class called TestLazy and declare a variable of type Lazy, then pass an anonymous function to the constructor of the Lazy class to calculate a value. We will use the value of this variable to test the correctness of lazy loading and singleton pattern.
to calculate a value. We will use the value of this variable to test the correctness of lazy loading and singleton pattern.
javaCopy code publicclassTestLazy { publicstatic void main(String[] args) { Lazy<Integer> lazyValue = new Lazy<>(() -> { int result = 100 + 200; System.out.println("Calculating value..."); return result; }); System.out.println("Before calling get()"); // first call int value1 = lazyValue.get(); System.out.println("After calling get()"); // second call int value2 = lazyValue.get(); System.out.println("After calling get() again"); System.out.println("value1: " + value1); System.out.println("value2: " + value2); // Check if it is the same object System.out.println("Is same instance: " + (lazyValue == lazyValue)); } }
After running this test class, the output we expect to see is:
vbnetCopy code Before calling get() Calculating value... After calling get() After calling get() again value1:300value2:300Is same instance: trueCopy code
The output shows that the first time the get() method is called, the function that computes the value is called and the value is computed. In the second call to the get() method, we don’t see the “Calculating value…” output, which proves that lazy loading is correct. In addition, we also checked whether the values obtained twice are equal, and whether the objects are the same instance, which proves the correctness of the singleton pattern.
Finally, we now have a Lazy class that implements lazy loading, using the Supplier interface to implement lazy loading and the singleton pattern, allowing us to easily delay the calculation of values while avoiding the problem of initializing variables multiple times.
The knowledge points of the article match the official knowledge files, and you can further learn relevant knowledge. Java skill treeHomepageOverview 108563 people are studying systematically