Lazy load / lazy mode

Lazy load / lazy mode
  1. Delay loading / lazy mode parsing

What is delayed loading? Delayed load is created when the get() method is called. The common method is to instantiate new in the get() method. Lazy load / lazy mode is created when a method is called.

public class MyObject {

    private static MyObject myObject;

    public MyObject() {
    }

    public static MyObject getInstance(){
        if(myObject!=null){
        }else {
            myObject = new MyObject();
        }
    }
}
public class MyThread extends Thread{
    @Override
    public void run() {
        System.out.println(MyObject.getInstance().hashCode());
    }
}
public class Run {

    public static void main(String[] args) {

        MyThread myThread = new MyThread();
        myThread.start();
        MyThread myThread1 = new MyThread();
        myThread1.start();
        MyThread myThread2 = new MyThread();
        myThread2.start();
    }
}

Although this experiment obtains an instance of an object, if it is in a multithreaded environment, it will take out multiple instances, which is contrary to the original intention of the single instance mode

  1. Lazy loading / lazy mode disadvantages

The code in the previous delay load example is completely wrong. It is impossible to maintain the state of singleton at all. Take a look at how to create multiple instances in a multithreaded environment in combination with the wrong single instance mode.

public class MyObject {
    private static MyObject myObject;

    public MyObject() {
    }

    public static MyObject getInstance(){
        try{
            if(myObject !=null){
            }else {
                //The simulation does some preparatory work before creating the object
                Thread.sleep(3000);
                myObject = new MyObject();
            }
        }catch (InterruptedException e){
            e.printStackTrace();
        }
        return myObject;
    }
}
public class MyThread extends Thread{
    @Override
    public void run() {
        System.out.println(MyObject.getInstance().hashCode());
    }
}
public class Run {
    public static void main(String[] args) {
        MyThread t1 = new MyThread();
        MyThread t2 = new MyThread();
        MyThread t3 = new MyThread();

        t1.start();
        t2.start();
        t3.start();
    }
}

There are two kinds of hashcode s, indicating that two objects are created, which is not a singleton. This is the wrong singleton mode.

  1. Solutions for lazy loading / lazy mode
  • Declare synchronized keyword Since multiple threads can enter the getInstance() method at the same time, you only need to declare the synchronized keyword on the getInstance() method.
public class MyObject {
    private static  MyObject myObject;

    public MyObject() {
    }
    //The whole method is locked, and the efficiency of setting synchronization method is too low
    //This method adds the synchronized keyword to get the object of the same instance, but the efficiency of this method is too low
    //If the next thread wants to get the object, it must wait for the previous object to release the lock before it can continue to run.
    public static synchronized MyObject getInstance(){
        try {
            if (myObject != null) {
            } else {
                //Simulation does some preparatory work before creating objects
                Thread.sleep(3000);
                myObject = new MyObject();
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return myObject;
    }
}
public class MyThread extends Thread{
    @Override
    public void run() {
        System.out.println(MyObject.getInstance().hashCode());
    }
}
public class Run {
    public static void main(String[] args) {
        MyThread myThread0 = new MyThread();
        MyThread myThread1 = new MyThread();
        MyThread myThread2 = new MyThread();
        myThread0.start();
        myThread1.start();
        myThread2.start();
    }
}

This method adds the synchronized keyword to get objects of the same instance, but the running efficiency of this method is very low. If the next thread wants to get objects, it must wait until the previous thread releases the lock before it can continue to execute.

  • Try to synchronize code blocks
public class MyObject {

    private static MyObject myObject;

    public MyObject() {
    }

    public static MyObject getInstance(){
        synchronized (MyObject.class) {
            try {
                if (myObject != null) {
                } else {
                    //The simulation does some preparatory work before creating the object
                    Thread.sleep(3000);
                    myObject = new MyObject();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return myObject;
        }
    }
}
public class MyThread extends Thread{
    @Override
    public void run() {
        System.out.println(MyObject.getInstance().hashCode());
    }
}
public class Run {
    public static void main(String[] args) {
        MyThread myThread1 = new MyThread();
        MyThread myThread2 = new MyThread();
        MyThread myThread3 = new MyThread();
        myThread1.start();
        myThread2.start();
        myThread3.start();
    }
}

This method adds synchronized statement block to get objects of the same instance, but the running efficiency of this method is also very low. It runs synchronously as synchronized synchronization method.

  • Separate synchronization for some important code
public class MyObject {

    private static  MyObject myObject;

    public MyObject() {
    }

    public static MyObject getInstance(){
        try {
            if (myObject != null) {
            } else {
                //The simulation does some preparatory work before creating the object
                Thread.sleep(3000);
                //Use synchronized(MyObject.class)
                //Although some codes are locked
                //But there are still non thread safety problems
                synchronized (MyObject.class) {
                    myObject = new MyObject();
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return  myObject;
    }
}
public class MyThread extends Thread{
    @Override
    public void run() {
        System.out.println(MyObject.getInstance().hashCode());
    }
}
public class Run {

    public static void main(String[] args) {

        MyThread myThread0 = new MyThread();
        MyThread myThread1 = new MyThread();
        MyThread myThread3 = new MyThread();

        myThread0.start();
        myThread1.start();
        myThread3.start();
    }
}

This method synchronizes the synchronized statement block and only synchronizes the key code of the instantiated object, The efficiency of operation has indeed been improved. However, if you encounter multithreading, you still can't get the result of the same instance object.

  • Use DCL double check lock mechanism
public class MyObject {

    private volatile static MyObject myObject;

    public MyObject() {
    }

    //Using double checking mechanism to solve the problem can ensure asynchronous execution without synchronous code
    //It also ensures the effect of single case

    public static MyObject getInstance(){

        if(myObject!=null){

        }else {
            synchronized (MyObject.class){
                if(myObject==null){
                    myObject = new MyObject();
                }
            }
        }
        return myObject;
    }
    /**
     * This version of the code is called double check locking
     */
}
public class MyThread extends Thread{
    @Override
    public void run() {
        System.out.println(MyObject.getInstance().hashCode());
    }
}
public class Run {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        MyThread myThread1 = new MyThread();
        MyThread myThread2 = new MyThread();
        myThread.start();
        myThread1.start();
        myThread2.start();
    }
}

Using the double check lock function, the problem of multithreading in "lazy mode" is solved successfully. DCL is also the solution used by most multithreading combined with singleton mode.

Tags: Programming

Posted on Thu, 13 Feb 2020 03:03:48 -0500 by pwicks