singleton单例模式小结

1.饿汉模式

public class SingletonEntity2 {

    // 在类加载的时候创建对象:饿汉模式
    public static SingletonEntity2 obj = new SingletonEntity2();
    
    // 构造方法私有化
    private SingletonEntity2(){}
    
    public static SingletonEntity2 getInstance(){
        return obj;
    }
    
}

2.懒汉模式

public class SingletonEntity {
    
    // 静态变量存放在方法区中,类加载的时候赋值,而且只会赋值一次,懒汉模式
    public static SingletonEntity obj = null;
    
    // 构造方法私有化
    private SingletonEntity() {}
    
    // 对外提供获取实例的公开的静态的方法
    public static SingletonEntity getInstance() {
        if (obj == null) {
            obj = new SingletonEntity();
            System.out.println("新创建实例");
        }
        System.out.println("直接返回实例");
        return obj;
    }
    
}

3.测试类

public static void main(String[] args) {
    
    SingletonEntity obj1 = SingletonEntity.getInstance();
    SingletonEntity obj2 = SingletonEntity.getInstance();
    System.out.println(obj1 == obj2); // true

}

==========================================================================================================================================

懒汉模式不安全性测试:

1.起现成类:

public class RunnableThreadTest implements Runnable {
    
    @Override
    public void run() {
        
        SingletonEntity obj = SingletonEntity.getInstance();
        System.out.println(Thread.currentThread().getName()+" "+obj);  

    }

}

2.测试类:

public class SingletonTest {

    public static void main(String[] args) {
        
        Thread thread1 = new Thread(new RunnableThreadTest());
        Thread thread2 = new Thread(new RunnableThreadTest());
        thread1.start();
        thread2.start();
        
    }

}

3.运行结果:

Thread-0 com.beijing.singleton.SingletonEntity@406866f9
Thread-1 com.beijing.singleton.SingletonEntity@25eb939e

==========================================================================================================================================

改善结果:推荐使用双检查锁机制

public class SingletonEntity {

    // 静态变量存放在方法区中,类加载的时候赋值,而且只会赋值一次,懒汉模式
    public static volatile SingletonEntity obj = null;

    // 构造方法私有化
    private SingletonEntity() {
    }

    // 对外提供获取实例的公开的静态的方法
    public static SingletonEntity getInstance() {
        try {
            // 双检查所机制
            if (obj == null) {
                synchronized (SingletonEntity.class) {
                    if (obj == null) {
                        Thread.sleep(1000);
                        obj = new SingletonEntity();
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return obj;
    }

}
为什么要用volatile修饰instance?
原因:在于instance = new SingletonEntity()的时候,在内存中实际上是分3步执行的:
1)分配对象的内存空间:memory = allocate();
2)初始化对象:ctorInstance(memory);
3)指向分配的地址:instance =memory
多线程在执行的时候,2 3可能发生重排序。即有可能线程A执行到第3步的时候,读取到instance不为null,就返回。实际上此时还未执行第二部即未初始化。
加上volatile就可以避免2 3步重排序来保证线程安全。
原文地址:https://www.cnblogs.com/zhangjianbing/p/8066526.html