Welcome to search “little monkey technical notes” to follow my public account, you can timely communicate with me if you have any questions.
DCL (double-checked Locking) Double-checked Locking. In Java multithreading, it is sometimes necessary to use lazy initialization to reduce the overhead of initializing classes and creating objects, using double-checking as a common technique for lazy initialization. However, using thread-safe delay initialization correctly requires some finesse, or problems can easily arise.
Let’s start with this code. The following code is an implementation of a typical lazy-loading singleton pattern, using lazy loading to reduce synchronization overhead. Guess if it has thread safety issues:
public class Singleton {
private static Singleton instance;
private Singleton(a) {}public static Singleton getInstance(a) {
// First check if instance is empty
if (instance == null) {
// lock instance initialization
synchronized (Singleton.class) {
// Check again if instance is empty
if (instance == null) {
instance = newSingleton(); }}}returninstance; }}Copy the code
It may seem perfect from the code. Because if instance is not null the first time, the locking method is not continued and instance is returned directly. This does significantly reduce the performance overhead associated with synchronized. If null, the locking method continues. If a thread holds a lock, it checks again to see if instance is null and instantiates it if it is not.
Maybe it’s perfect as you see it, because it’s wrong. If the first check for instance is not null, the object referenced by instance may not have been initialized.
The purpose of the above code “instance = new Singleton()” is to create an object. This line of code from scratch can go through the following steps:
Note: On some JIT compilers, it is possible to reorder steps 2 and 3. The order of execution after reordering is as follows:
So let’s go back to the code example above: assuming this singleton has not been initialized, it also allows the JIT compiler to reorder steps 2 and 3. There are two threads accessing the singleton at the same time, so it is possible that one of the threads is accessing an uninitialized object.
Let’s do A parsing: Suppose thread A accesses the singleton first, and then goes to step 2 after the reorder, thread B accesses the singleton. If the singleton is already in memory, it will be initialized by someone else. But what it actually gets is an uninitialized singleton.
So the above example is not a safe singleton lazy load.
If you read my previous article on keywords that prohibit reordering, you should be able to think of volatile. So the code above requires only a few minor modifications to achieve thread-safe lazy initialization:
public class Singleton {
// Add the volatile keyword to forbid instruction reordering
private static volatile Singleton instance;
private Singleton(a) {}public static Singleton getInstance(a) {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = newSingleton(); }}}returninstance; }}Copy the code
In “Private static volatile Singleton instance;” Adding a volatile keyword effectively disables instruction reordering to address the problem of simultaneous access by multiple threads caused by the DCL.
Please note that I said “first time”, because instance is fixed with the static keyword, so it is global once it is initialized, so the problem with multithreading is also the problem with the first concurrent access.
Welcome to search “little monkey technical notes” to follow my public account, you can timely communicate with me if you have any questions.