[设计模式]你不是对单例模式比较熟吗?你倒是写一个线程安全的出来呀!

编程入门 行业动态 更新时间:2024-10-27 06:20:18

[设计<a href=https://www.elefans.com/category/jswz/34/1771241.html style=模式]你不是对单例模式比较熟吗?你倒是写一个线程安全的出来呀!"/>

[设计模式]你不是对单例模式比较熟吗?你倒是写一个线程安全的出来呀!

单例模式比较好理解,就是保证只有一个对象被创建

如果是单线程下代码还比较好写一些:

/***饿汉模式* 单例实例在类装载时进行创建* 线程安全*/
public class SingletonExample2 {// 私有构造函数private SingletonExample2(){}// 单例对象private static SingletonExample2 instance = new SingletonExample2();// 静态的工厂方法public static SingletonExample2 getInstance(){return instance;}
}

上面的是饿汉模式,在类加载时就开始创建
懒汉模式就比较懒,在使用的时候才会创建

/***懒汉模式* 单例实例在第一次使用时进行创建* 线程安全--并不推荐,因为带来了性能上的开销*/
public class SingletonExample3 {// 私有构造函数private SingletonExample3(){}// 单例对象private static SingletonExample3 instance = null;// 静态的工厂方法public static synchronized SingletonExample3 getInstance(){if (instance == null){instance = new SingletonExample3();}return instance;}
}

如果是在单线程环境下,上面的代码是没有任何问题的
但是如果是在多线程环境下呢?
现在同时有线程 A 和 B 要创建线程,此时线程 A 拿到了 instance 的值为 null ,然后 CPU 停止了当前线程 A ,线程 B 开始运行,也拿到了 instance 的值为 null ,接下来线程 A 和 B 都会去创建
怎么办呢?加个双重检测机制,再加个锁

/***懒汉模式-->双重同步锁模式* 单例实例在第一次使用时进行创建* 线程不安全*/
public class SingletonExample4 {// 私有构造函数private SingletonExample4(){}// 1, memory = allocate() 分配对象的内存空间// 2, ctorInstance() 初始化对象// 3, instance = memory 设置 instance 指向刚分配的内存// JVM 和 cpu 优化时,会发生指令重排// 有可能发生 1,3,2//此时会导致线程不安全// 单例对象private static SingletonExample4 instance = null;// 静态的工厂方法public static SingletonExample4 getInstance(){if (instance == null){   // 使用了双重检测机制synchronized (SingletonExample4.class) {   // 同步锁if(instance == null) {instance = new SingletonExample4();}}}return instance;}
}

这样双重检测再加锁看似是没有问题了
但是还记得吗? JVM 是会指令重排的,本来 1,2,3 运行下来没问题,结果呢,指令重排之后就变成了 1,3,2 ,还是两个线程,线程 A 拿到第一个的 instance 为 null ,线程 B 拿到的是指令重排之后的第二个 instance 为 null ,此时仍然有线程不安全的问题
那我不让它指令重排不就好了? volatile 就要大显身手了

/***懒汉模式-->双重同步锁模式* 单例实例在第一次使用时进行创建*/
public class SingletonExample5 {// 私有构造函数private SingletonExample5(){}// 1, memory = allocate() 分配对象的内存空间// 2, ctorInstance() 初始化对象// 3, instance = memory 设置 instance 指向刚分配的内存// JVM 和 cpu 优化时,会发生指令重排// 有可能发生 1,3,2//此时会导致线程不安全// 单例对象--- volatile + 双重检测机制-->禁止指令重排private  volatile static SingletonExample5 instance = null;// 静态的工厂方法public static SingletonExample5 getInstance(){if (instance == null){   // 使用了双重检测机制synchronized (SingletonExample5.class) {   // 同步锁if(instance == null) {instance = new SingletonExample5();}}}return instance;}
}

上面都是对懒汉模式的优化,饿汉模式也想线程安全,该咋办嘞

/***饿汉模式* 单例实例在类装载时进行创建* 线程安全--->要注意 private static 和 static 的先后执行顺序*/
public class SingletonExample6 {// 私有构造函数private SingletonExample6(){}// 单例对象private static SingletonExample6 instance = null;static{instance = new SingletonExample6();}// 静态的工厂方法public static SingletonExample6 getInstance(){return instance;}public static void main(String[] args) {System.out.println(getInstance().hashCode());System.out.println(getInstance().hashCode());}
}

还有一种最安全的方法:

/*** 线程安全---最安全* 推荐使用*/
public class SingletonExample7 {// 私有构造函数private SingletonExample7(){}public static SingletonExample7 getInstance(){return Singleton.INSTANCE.getInstance();}private enum Singleton{INSTANCE;private SingletonExample7 singleton;// JVM 保证这个方法绝对只调用一次Singleton(){singleton = new SingletonExample7();}public SingletonExample7 getInstance(){return singleton;}}
}

以上,感谢您的阅读哇~

更多推荐

[设计模式]你不是对单例模式比较熟吗?你倒是写一个线程安全的出来呀!

本文发布于:2024-03-23 17:51:57,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1741049.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:模式   你不是   线程   来呀

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!