Learn more about DCL
Learn more about DCL
1
1. What is DCl?
1
2. Reasons Why DCL was insecure in the past
2
2.1 jmm Defects
2
Constructor escape problems caused by 2.2reorder
2
3. Try to fix DCL
2
3.1 modify the field resource with volatile
2
3.2 cheated the Compiler
3
4. Why is some DCL secure now?
3
4.1 starting from JSR-133: Corrected jmm
4
4.1.1 [Final]
4
4.1.2 [volatile]
4
4.1.3 [happens-before]
4
5. Reasons Why DCL is not recommended
5
6. Perfect replacement of DCL
5
References
5
1. What is DCl?
DCL: double-checked locking"
The code format is usually as follows:
Class someclass {
Private resource = NULL;
Public resource getresource (){
If (resource = NULL) {// Checkpoint 1
Synchronized {
If (resource = NULL) // Checkpoint 2
Resource = new resource ();
}
}
Return resource;
}
}
The two checkpoints in the preceding code comments constitute the so-called "double check ".
Its original intention is:
The resource is loaded with inertia.
Avoid frequent access to synchronized synchronization blocks to improve concurrency performance.
2. Reasons Why DCL was insecure in the past 2.1 jmm Defects
Before jvm1.4 was launched, JVM's access to memory was based on the original jmm (Java Memory Model) specification. It tried to define a consistent and cross-platform memory model, describes the memory access rules in the case of multithreading, but unfortunately it is flawed. Under the constraints of the original jmm, some strange and chaotic situations are still allowed. A typical example is to assign a value to the final field in the constructor. What another thread may see is:
The default value of the final field, rather than the value provided by the object in the constructor.
The reasons for these problems are as follows:
Constructor escape problems caused by 2.2reorder
Reoder, I understand that during compilation and runtime, the compiler or JVM can disrupt the execution sequence of the final output assembly code to optimize the program execution performance. This sequence may be completely different from the execution sequence of the "visible" program in the Java source code. For example, a simple sentence
Resource = new resource ();
After being converted to assembly, there are at least three steps:
Allocate space for the resource object in the heap
Execute the resource Constructor
Assign the reference of the newly generated resource object to the resource field.
After reorder, the execution steps of the preceding three items are likely to change to 1, 3, and 2.
Therefore, in the case of multithreading, other threads may access invalid references of a constructor when the resource is not null but not executed. This makes Checkpoint 1 of DCL no longer reliable.
3 try to fix DCL 3.1 use volatile to modify the field Resource
Class someclass {
Private volatile resource = NULL;
Public resource getresource (){
If (resource = NULL ){
Synchronized {
If (resource = NULL)
Resource = new resource ();
}
}
Return resource;
}
}
Before jvm1.4, volatile only ensures that when a write operation is performed on the modified object, the write operation itself will not be reordered, and the written value will be immediately updated to the primary storage, to ensure that the volatile objects seen by all threads are consistent (All threads will be forced to get data from the main memory rather than the thread cache or multi-core CPU registers/high-speed cache ); however, it still allows write operations on volatile objects to be mixed with write operations on non-volatile objects to be reordered. The tragedy remains the same, unless all fields in the resource class are modified with volatile.
3.2 cheated the Compiler
The Code is as follows:
Public resource getresource (){
If (resource = NULL ){
Synchronized {
If (resource = NULL ){
Resource temp = new resource (); // Step 1
Resource = temp; // Step 2
}
}
Return resource;
}
When a temporary variable is used, it seems that the result will be how the constructor is re-ordered. When Step 2 is executed, the constructor must have completed. Unfortunately, in fact, the compiler's optimization options are likely to relentlessly remove this temporary variable from the bytecode, which is obviously redundant. Even if the compiler optimization is bypassed, it still does not work, because the compiler is only one of the potential reorder drivers, and the processor and cache will still work at runtime. Since the Modern processor can deduce whether there is any dependency between two commands, it will decide whether to process these commands in parallel or out of order. Similarly, the write-back cache of each thread changes the data write-back sequence when multiple data entries are about to be updated to the primary storage.
Therefore, reorder behavior is unpredictable and cannot be bypassed at the Java source code level.
Conclusion: The DCl cannot be repaired.
4. Why is some DCL secure now?
In a recent email discussion about DCl, it was mentioned that no problem was found in the online environment using DCL. Why? First, the occurrence of reorder is dependent on the specific JVM implementation, even before jvm1.4, there is also a small part of JVM can be in some of the hardware to use DCL; secondly, with the launch of the JSR-133, jdk1.4 has partially corrected jmm, while jvm1.5 has completely corrected jmm, and we currently use jdk1.6 online. In the corrected jmm, As long as volatile is used together, DCL is safe.
4.1 starting from JSR-133: Corrected jmm
The jmm defined in the JSR-133 ensures the visibility of memory operations across threads and ensures the semantics of volatile, synchronized, and final.
4.1.1 [Final]
As mentioned in the "jmm defects" section, when synchronization is not used, the other thread will first see the default value of the final field and then see the correct value. This is inconsistent with the final semantics. In the new jmm, the final semantics is guaranteed by implementing the following:
Write the final field before other threads load the shared reference of the final field. (Final fields must be correctly assigned values before other threads can read them)
After the constructor is executed, all the writes to the final field and variables indirectly accessible through these final fields become "Frozen ", all threads that obtain reference to this object after freezing will be able to see the frozen value of all frozen fields. (All threads have consistent visibility into final and its indirect fields)
Writing the initialized final field will not be reordered together with the operation after freezing associated with the constructor. (Inside the constructor, for a final field, the operation before the freeze point must be prior to the operation after the freeze point)
4.1.2 [volatile]
In the new memory model, the problem described in "Try 1. Modify Field resource with volatile" has changed, currently, the read and write operations on the volatile field cannot be reordered together with other memory operations. When thread a writes the volatile variable V and thread B reads V, all variables visible to a can be visible to B. The result is a more volatile semantics (originally, only the visibility of all threads when the volatile field itself is read and written is ensured, and the visibility of itself and all related fields when the volatile field is read and written is now ensured ), this has led to some potential risks, but most developers take it for granted that the code is feasible, at the cost of access
The performance overhead of the volatile field is far from the past.
Therefore, using DCL with volatile modification is safe and feasible in the new memory model.
4.1.3 [happens-before]
In addition, the JSR-133 also corrected some other problems in the original jmm, these corrections are reflected in the following so-called "happens-before" law, for more information, see references.
- Each action in a thread happens-before every action in that thread that comes later in the program order
- An unlock on a monitor happens-before every subsequent lock on that same monitor
- A write to a volatile field happens-before every subsequent read of that same volatile
- A call to thread. Start () on a thread happens-before any actions in the started thread
- All actions in a thread happen-before any other thread successfully returns from a thread. Join () on that thread
A happens-before B means that the execution of a must be prior to B. The previous guarantees of final semantics can be understood as the specific embodiment of the above happens-before law.
5. Reasons Why DCL is not recommended
At the beginning of the article, we mentioned that the purpose of using DCL is to load and improve the performance in a inert manner. If volatile is not used, the reliability of DCL cannot be guaranteed; otherwise, the volatile semantics is adjusted and enhanced in the new jmm, the side effects of volatile make the performance overhead of volatile almost the same as that of synchronization blocks. Therefore, although the DCl with volatile is reliable, it is not recommended.
6. Perfect replacement of DCL
Implement inert loading through internal classes:
Public class Singleton {
Private Singleton (){... } Private Static class singletoncontainer {Private Static Singleton instance = new Singleton ();} public static Singleton getinstance () {return singletoncontainer. instance ;}}
JVM ensures that the loading process of classes is mutually exclusive by threads. In this way, when getinstance is called for the first time, the instance is created only once and the memory assigned to the instance has been initialized, which avoids reorder; in addition, this method only uses the mutex mechanism when it is called for the first time, which solves the performance problem caused by each use of synchronization blocks. The instance is loaded only when the getinstance method is called for the first time, therefore, it also implements inert loading.
References
Java Theory and Practice: Restoration
Java memory model, part 1
Http://www.ibm.com/developerworks/cn/java/j-jtp02244/
Java Theory and Practice: Restoration
Java memory model, part 1
Http://www.ibm.com/developerworks/cn/java/j-jtp03304/
Java Theory and Practice: Correct Use
Volatile variable
Http://www.ibm.com/developerworks/cn/java/j-jtp06197.html
Double-checked locking: Clever, but broken
Http://www.javaworld.com/jw-02-2001/jw-0209-double.html
Can double-checked locking be fixed?
Http://www.javaworld.com/javaworld/jw-05-2001/jw-0525-double.html
JSR-133 FAQ
Http://blog.sina.com.cn/s/blog_4e459c3701000ad5.html