Home>Article>Operation and Maintenance> How to analyze double check locking in JAVA language
In program development, sometimes it is necessary to postpone some high-cost object initialization operations and only initialize them when these objects are used. In this case, you can Use double-checked locking to delay object initialization operations. Double-check locking is a software design pattern designed to reduce competition and synchronization overhead in concurrent systems. Based on the ordinary singleton pattern, it first determines whether the object has been initialized, and then decides whether to lock it. Although double-checked locking solves the error-prone and thread-unsafe problems of ordinary singleton patterns in multi-threaded environments, there are still some hidden dangers. The following takes the JAVA language source code as an example to analyze the causes and repair methods of double-check locking defects.
Double check locking has no impact in a single-threaded environment. In a multi-threaded environment, due to Threads will switch executions at any time. When instructions are rearranged, the object is not completely instantiated, resulting in program call errors.
The example comes from Samate Juliet Test Suite for Java v1.3 (https://samate.nist.gov/SARD/testsuite.php ), source file name: CWE609_Double_Checked_Locking__Servlet_01.java.

The above code lines are 23 to 38. The program first determines whetherstringBadIs null, if not, theStringobject will be returned directly, thus avoiding the resources required to enter thesynchronizedblock. Use thesynchronizedkeyword to avoid multiple creations ofStringobjects in a multi-threaded environment whenstringBadis null. When the code is actually run, errors may still occur in the above code.
For line 33, the creation of thestringBadobject and the assignment operation are performed in two steps. But the JVM does not guarantee the order of these two operations. When the instructions are reordered, the JVM will first assign the value pointing to the memory address, and then initialize thestringBadobject. If there are two threads at this time, both threads enter line 27 at the same time. Thread 1 first enters thesynchronizedblock, and sincestringBadis null, it executes line 33. When the JVM reorders the instructions, the JVM first allocates the empty memory of the instance and assigns it tostringBad, but at this time thestringBadobject has not yet been instantiated, and then thread 1 leftsynchronizedblocks. When thread 2 enters thesynchronizedblock, sincestringBadis not null at this time, the uninstantiated object is directly returned (only the memory address value, the object is not actually initialized). When subsequent thread 2 calls the program to operate on thestringBadobject, the object at this time has not been initialized, so an error occurs.
Use 360 Code Guard to detect the above sample code, and you can detect the "double check lock" defect, and the display level is medium. The defect is reported at line 27 of the code, as shown in Figure 1:

Figure 1: Detection example of "Double Check Lock"

volatilekeyword in line 23 to modify the singleton variablestringBad.volatileAs an instruction keyword, it ensures that the instruction will not be omitted due to compiler optimization and requires direct reading of the value each time.volatilekeyword can solve this problem semantically. It is worth noting that the prohibition of instruction reordering optimization function ofvolatilewas only implemented in Java 1.5, so the version before 1.5 is still is unsafe, even if thevolatilekeyword is used.Use 360 Code Guard to detect the repaired code, and you can see that the "double check lock" defect no longer exists. As shown in Figure 2:

To avoid double-check locking, you need to pay attention to the following points:
(1) Use the volatile keyword to avoid instruction reordering, but this solution requires JDK5 or higher, because it is used starting from JDK5 The new JSR-133 memory model specification, which enhances the semantics of volatile.
(2) Solution based on class initialization.
The JVM will perform the initialization of the class during the initialization phase of the class (that is, after the Class is loaded and before it is used by the thread). During the initialization of the execution class, the JVM will acquire a lock. This lock can synchronize the initialization of the same class by multiple threads.
The above is the detailed content of How to analyze double check locking in JAVA language. For more information, please follow other related articles on the PHP Chinese website!