技术学习笔记
Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode

6.1立即加载与延迟加载

立即加载

MyObject.java
public class MyObject {
    private static MyObject myObject = new MyObject();
    private MyObject(){}
    public static MyObject getInstance(){
        //该方法未同步
        return myObject;
    }
}

MyThread.java
public class MyThread extends Thread{
    @Override
    public void run(){
        System.out.println(MyObject.getInstance().hashCode());
    }
}
Run.java
public class Run {
    public static void main(String[] args) {
        MyThread A = new MyThread();
        MyThread B = new MyThread();
        MyThread C = new MyThread();

        A.start();
        B.start();
        C.start();
    }
}

执行结果

468440919
468440919
468440919

三个线程获得的对象的 hash 值一样,说明是同一个对象。

延迟加载(懒加载)

修改 MyObjec.java
public class MyObject {
    private static MyObject myObject ;
    private MyObject(){}
    public static MyObject getInstance(){
        //该方法未同步
        if (myObject == null)myObject = new MyObject();
        return myObject;
    }
}

运行结果

496361680
1990702044
1990702044

因为 getInstance() 没有加锁同步,所以会有生成多个实例的情况,违背了单例模式。

解决『延迟加载违背单例模式』这一问题

为getInstance() 加 synchronized,同步内容过多,对总体效率不利

修改 MyObject.java,加上 synchronized

public class MyObject {
    private static MyObject myObject ;
    private MyObject(){}
    synchronized public static MyObject getInstance(){
        //已同步
        if (myObject == null)myObject = new MyObject();
        return myObject;
    }
}

使用同步块,仍然会有不同步,可能产生多个实例而违背单例模式

修改 MyObject.java,添加同步块。

public class MyObject {
    private static MyObject myObject ;
    private MyObject(){}
    public static MyObject getInstance(){
        try{
            if(myObject == null){
                Thread.sleep(2000);//模拟对象属性配置耗时
                synchronized (MyObject.class){
                        myObject = new MyObject();
                }
            }
        }catch (InterruptedException e){
        }
        return myObject;
    }
}
DCL 双检查锁机制,完全解决

修改 MyObject.java,两次检查 MyObject 是否为 null。

public class MyObject {
    private static MyObject myObject ;
    private MyObject(){}
    public static MyObject getInstance(){
        try{
            if(myObject == null){
                Thread.sleep(2000);//模拟对象属性配置耗时
                synchronized (MyObject.class){
                    if (myObject == null){
                        myObject = new MyObject();
                    }
                }
            }
        }catch (InterruptedException e){
        }
        return myObject;
    }
}