Multithreaded notes - single example

Keywords: Java

Single instance creation. There are many examples on the Internet. I just take notes here. Maybe it's not more detailed than others. It's mainly to make some cloud notes for myself

1. hungry man

public class Ehan  {
    //1. Provide a static instance
    private final static Ehan instance = new Ehan();

    //2. Privatization constructor
    private Ehan(){}

    //Provide a method to obtain an external instance
    public  static Ehan getInstance(){        return instance;
    }
}

Test:

public static void main(String[] args){

        for (int i = 0; i < 100; i++) {
            new Thread(() -> {
                Ehan obj = Ehan.getInstance();
                System.out.println(obj.hashCode());
            }, "thread" + i).start();
        }
}

Result:

All hashcode s are the same, indicating the same instance

Advantages: thread safe

Disadvantages: when a class is loaded, it will be instantiated (if other static properties or static methods of the class are used, it will be instantiated, but in fact, I may not need it to be instantiated). If I do not use this class later, it is a waste

 

2. slacker

public class LanHan {
    //1. Define a static variable
    private static LanHan instance;

    //2. Privatization constructor
    private LanHan(){}

    //3. Provide a method to obtain an external instance
    public synchronized static LanHan getInstance(){
        if(instance == null){            
            instance = new LanHan();
        }
        return  instance;
    }
}

synchronized on getInstance() cannot be saved, which may cause problems

The test method still uses the above test method, just change the class

Modify the getInstance() method, kill synchronized, and add a sleep before creation to simulate other operations, which takes a little time

public static LanHan getInstance(){
    if(instance == null){
        try {
            Thread.sleep(500);
        }
        catch (InterruptedException e) {
            e.printStackTrace();
        }
        instance = new LanHan();
    }
    return  instance;
}

Results:

 

There are different results here. It is found that instead of creating a single instance, different instances are created

This is because there is no lock on the method, and different threads can come in. Then many threads stop at the place where they sleep, and the later threads catch up and also sleep

When hibernation is complete, continue to execute the code and create the instance

Advantages and disadvantages of lazy mode:

Advantage:

1. It overcomes the problem of loading and creating in hungry mode. When the getInstance() method is called, the instance will be created. It is equivalent to loading on demand

2. Thread safety

Disadvantages:

1. Every time getInstance() is called, a null judgment will be performed

2. getInstance() method is locked. When it is called concurrently, it needs to be queued. When one thread releases the lock, other threads need to compete for the lock

 

3. Double judgment

/**
 * double checked locking
 **/
public class DCL {

    //1. Provide a static reference
    private static volatile DCL instance;

    //2. Privatization constructor
    private DCL(){}

    //3. Provide an external access instance interface
    public static DCL getInstance(){
        if(instance == null){
            synchronized (DCL.class){
                if(instance == null){
                    instance = new DCL();
                }
            }
        }
        return instance;
    }
}

Result:

 

Judge again in the lock to ensure thread safety

Similarly, make a small change to the getInstance() method here:

public static DCL getInstance() {
    if (instance == null) {
        try {
            Thread.sleep(500);
        }
        catch (InterruptedException e) {
            e.printStackTrace();
        }
        synchronized (DCL.class) {
            // if(instance == null){
            instance = new DCL();
            // }
        }
    }
    return instance;
}

Here, I will comment out the judgment in the lock, and add a sleep outside the lock. Let's see if it works:

 

In the same way,

Article 1 when a thread comes in, it is empty √ and goes to sleep

When the second thread comes in, it is empty √ to enter sleep. The first thread may still be in sleep, let alone create an instance

......

Some logic processing may take time. When an instance is created, it may not only need new processing, but also need some logic processing before. It will take a little time, similar to the sleep effect here

So we need to add a null judgment in the lock. Because the code in the lock can only be executed by one thread, even if other logic processing takes time, the above situation will not occur\

Until this thread is created and another thread comes in, you can judge that the instance has been created

 

4. Internal static class mode

public class Inner {
    //1. Privatization constructor
    private Inner(){}

    //2. Static class
    private static class InnerBuilder{
        private final static Inner instance = new Inner();
    }

    //3. Provide a way to get an instance
    public static Inner getInstance(){
        return InnerBuilder.instance;
    }
}

In all methods, we can't save the step of privatizing the constructor. Otherwise, we can create it through the way of new, which is not a single example

Result:

This method is recommended

Advantages:

1. Thread safety

2. Simple code

3. No need to add lock (there is an initialization lock, but it is not added artificially)

4. Delay loading (internal classes can only be loaded when they are loaded by external classes)

 

5. enumeration class

public enum EnumObj {
    INSTANCE;
}

I haven't done it in this way

 

In general, the use of internal static classes on the line

Posted by QuizToon on Mon, 24 Feb 2020 03:47:10 -0800