定义:
饿汉式:
/** * 饿汉式. * * @author jialin.li * @date 2019-12-30 22:13 */ public class Singleton { private Singleton() { } private static Singleton singleton = new Singleton(); public Singleton getInstance(){ return singleton; } }
-
- 饿汉式的特点是类初始化的时候,创建了该对象。
- 由于类只会初始化一次,所以保证了对象只会被创建一次。
- 同时将构造方法私有化,保证了没有办法从外部创建对象。
懒汉式:
/** * 懒汉式. * * @author jialin.li * @date 2019-12-30 22:13 */ public class Singleton { private Singleton() { } private volatile Singleton singleton = null; public Singleton getInstance(){ // 提高性能,降低线程进入临界区的可能 if(singleton == null){ synchronized (Singleton.class){ if(singleton == null){ singleton = new Singleton(); } } } return singleton; } }
- 第一处判空,是为了提高性能,降低线程进入临界区的可能性。
- 第二处判空是为了线程同步,假如没有第二处判空,则可能两个线程都通过了if(singleton==null)条件,这样即使是临界区内只有一个线程在执行,临界区内的代码也会被执行两遍,这样就会产生两个对象,不符合单例模式。
- 保证变量在线程之间的可见性(直接从主存中读写数据,不经过工作内存)
- 阻止编译时和运行时的指令重排,编译时JVM编译器遵循内存屏障约束,运行时依赖CPU屏障来阻止指令重排。
- 开辟一块内存空间
- 创建对象
- 将对象的地址存入引用变量
- 开辟一块内存空间
- 将对象的地址存入引用变量
- 创建对象
假设发生了指令重排,线程A、B都执行这段代码,线程A执行到了new Singleton()的步骤2,此时还没有创建对象,这个时候发生了线程的切换。线程B开始执行,这个时候线程B还可以通过if(singleton == null)的判断,因为线程A中的singleton只是指向了一个空的内存地址,这个时候线程B创建出了一个Singleton对象,当线程切换成A时,线程A仍执行了new Singleton()的步骤3,此时创建了2个Singleton对象,不符合单例模式。
静态内部类单例模式:
/** * 静态内部类单例模式. * * @author jialin.li * @date 2019-12-30 22:13 */ public class Singleton { private Singleton() { } public static Singleton getInstance() { return Inner.singleton; } private static class Inner { private static Singleton singleton = new Singleton(); } }
枚举单例模式
public enum Singleton { INSTANCE //doSomething 该实例支持的行为 //可以省略此方法,通过Singleton.INSTANCE进行操作 public static Singleton get Instance() { return Singleton.INSTANCE; } }
期待您的关注、推荐、收藏,同时也期待您的纠错和批评。