More knowledge of java is required. (reposted below)

What is a publish object?

  Publishing an object means making an object usable by code outside the current scope

  What is object escape?

  Object escape is a false release, which means that when an object has not been constructed, it is visible to other threads

 

  escape-demo

copy code
@ Slf4j
public class Escape {

    private int thisCanBeEscape = 0;

    public Escape() {
        new InnerClass();
    }

    private class InnerClass{
        public InnerClass() {
            log.info("{}", Escape.this.thisCanBeEscape);
        }
    }

    public static void main(String[] args) {
        new Escape();
    }

}
copy code

  In this instance, the Escape object has not been constructed, and the member variable thisCanBeEscape of the object is accessed. This class is thread-unsafe, and it is not recommended to write in this way.

 

  Insecure release - demo

copy code
@ Slf4j
public class UnsafePublish {

    private String[] states = {"a", "b", "c"};

    public String[] getStates() {
        return states;
    }

    public static void main(String[] args) {
        UnsafePublish unsafePublish = new UnsafePublish();
        log.info("{}", Arrays.toString(unsafePublish.getStates()));

        unsafePublish.getStates()[0] = "d";
        log.info("{}", Arrays.toString(unsafePublish.getStates()));

    }
}
copy code

  The output is: [a,b,c] and [d,b,c] Objects published in this way are thread-unsafe, because there is no guarantee that other threads will modify the states field, resulting in a state error

 

  Four ways to safely publish objects:

  a. Initialize an object reference in a static initialization function

  b. Save the reference of the object to the volatile type field or the AtomicReference object

  c. Save a reference to the object in a final type field of a properly constructed object

  d. Save a reference to the object in a field protected by a lock

 

 How to safely publish an object?

 We use the implementation of different singletons to illustrate the method of safely publishing objects

 

  singleton-demo1

copy code
public class SingletonExample1 {

    //private constructor
    private SingletonExample1() {

    }
    // singleton object
    private static SingletonExample1 instance = null;

    // static factory method
    public static SingletonExample1 getInstance() {

        //There is no problem with single thread, there will be problems when multi-threaded
        if (instance == null) {
            instance = new SingletonExample1();
        }

        return instance;
    }
}
copy code

  There is no problem with this instance in single-threaded mode, but in multi-threaded mode, if two threads run at the same time to judge instance==null, it is possible to create two new instances, so this is thread unsafe Yes, this is also the lazy mode. This instance satisfies the a condition. If you add the d condition and lock it when judging whether it is null, it can become thread-safe.

 

  singleton-demo2

copy code
public class SingletonExample2 {

    //The hungry mode is insufficient. If there is too much processing in the construction method, it will cause the class to load very slowly.
    //private constructor
    private SingletonExample2() {

    }
    // singleton object
    private static SingletonExample2 instance = new SingletonExample2();

    // static factory method
    public static SingletonExample2 getInstance() {

        return instance;
    }
}
copy code

  This demo is thread-safe. Two points need to be paid attention to when using the hungry mode. One is that this class must be used (to avoid waste of resources), and the other is that there is not too much processing in the private construction method. 4

 

  singleton-demo3

copy code
public class SingletonExample3 {

    //private constructor
    private SingletonExample3() {

    }
    // singleton object
    private static SingletonExample3 instance = null;

    // static factory method
    public static synchronized SingletonExample3 getInstance() {

        //There is no problem with single thread, there will be problems when multi-threaded
        if (instance == null) {
            instance = new SingletonExample3();
        }

        return instance;
    }
}
copy code

  This demo is the case where demo1 is locked, which is thread-safe, but it is not recommended to write in this way, because although thread-safety is guaranteed, there is a certain overhead in performance.

 

  singleton-demo4

copy code
/**
 * Lazy mode double synchronization lock singleton mode
 * The singleton instance is created when it is used for the first time
 * The double detection mechanism is not necessarily thread-safe because of the existence of instruction reordering
 */
public class SingletonExample4 {

    //private constructor
    private SingletonExample4() {

    }


    // singleton object
    private static SingletonExample4 instance = null;

    // static factory method
    public static  SingletonExample4 getInstance() {

        //There is no problem with single thread, there will be problems when multi-threaded
        if (instance == null) { //Double detection mechanism

            //sync lock
            synchronized (SingletonExample4.class) {
                if (instance == null) {
                    instance = new SingletonExample4();
                }
            }

        }

        return instance;
    }

}
copy code

    This demo is an optimized version of lazy mode, but note that this demo is not thread-safe because there is instruction rearrangement. When instance=new SingletonExample4() is executed, the cpu will perform three steps: 1. memory=allocate() Allocate the memory space of the object 2, ctorInstance() initializes the object 3, instance = memory Set instance to point to the memory just allocated, but due to the optimization of jvm and cpu, instruction rearrangement will occur, such as the result of rearrangement becomes 1, 3, 2. There is no problem in the case of single thread, but problems may occur in the case of multi-threading. If thread A executes to instance=new SingletonExample4() at this time, instruction rearrangement occurs, and the second step is executed. 3. At this time, instance has executed the memory of the object, but the object has not been initialized. If thread B happens to execute if (instance==null) at this time, the condition is no longer established, and it returns directly because this object It has not been initialized, and problems may occur when using this object directly.

 

  Singleton-demo5

copy code
/**
 * Lazy mode double synchronization lock singleton mode
 * The singleton instance is created when it is used for the first time
 * The double detection mechanism is not necessarily thread-safe because of the existence of instruction reordering
 */
public class SingletonExample5 {

    //private constructor
    private SingletonExample5() {

    }

    //1, memory = allocate() allocates the memory space of the object
    // 2. ctorInstance() initializes the object
    // 3. instance = memeory set instance to point to the memory just allocated


    //Restrict instruction rearrangement through volatile and double detection mechanism, volatile restricts the write operation of code
    //Singleton object, instruction rearrangement occurs by volatile restriction code
    private volatile static SingletonExample5 instance = null;

    // static factory method
    public static SingletonExample5 getInstance() {

        //There is no problem with single thread, there will be problems when multi-threaded
        if (instance == null) { //Double detection mechanism

            //sync lock
            synchronized (SingletonExample5.class) {
                if (instance == null) {
                    instance = new SingletonExample5();
                }
            }

        }

        return instance;
    }
}
copy code

  This demo is an upgraded version of demo4. As long as the problem of instruction rearrangement is solved, in the previous blog "Thread Safety", we have introduced that volatile can limit the code to have instruction rearrangement. This demo is thread-safe.

 

  singleton-demo6

copy code
/**
 * Hungry mode
 * Singleton instance is created at class loading
 */
@ThreadSafe
public class SingletonExample6 {

    //The hungry mode is insufficient. If there is too much processing in the construction method, it will cause the class to load very slowly.
    //private constructor
    private SingletonExample6() {

    }
    //Initialize the static field of the singleton object
    private static SingletonExample6 instance = null;

    // static block method
    static {
        instance = new SingletonExample6();
    }
    
    // static factory method
    public static SingletonExample6 getInstance() {

        return instance;
    }

    public static void main(String[] args) {
        System.out.println(getInstance().hashCode());
        System.out.println(getInstance().hashCode());
    }
}
copy code

  demo2 is the static code field method of the hungry man mode, this demo is the static code block method of the hungry man mode, this demo is also thread-safe

 

   singleton-demo7

copy code
/**
 * Enumeration mode: safest
 * It is easier to ensure security than lazy mode
 * Compared with the hungry mode, the initial initialization is only done when the actual call is made
 */
public class SingletonExample7 {
    
    private SingletonExample7() {

    }
    // static factory method
    public static SingletonExample7 getInstance() {

        return Singleton.INSTANCE.getSingleton();
    }

    private enum Singleton{
        INSTANCE;
        private SingletonExample7 singleton;

        //JVM guarantees that this method is called absolutely only once, and is initialized before this class is called
        Singleton() {
            singleton = new SingletonExample7();
        }

        public SingletonExample7 getSingleton() {
            return singleton;
        }
    }

}
copy code

  This demo is our most recommended singleton writing method, and it is thread-safe. It is easier to guarantee in terms of security than the lazy mode. Compared with the hungry mode, the initial initialization is only done when the actual call is made.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325698926&siteId=291194637