java 并发编程学习笔记(四)之 安全发布对象(单例模式实现几种实现方式)

举报
小米粒-biubiubiu 发表于 2020/12/03 01:28:12 2020/12/03
【摘要】                                           安全发布对象 错误发布对象: 发布对象:使一个对象能被当前范围之外的代码所使用 ...

                                          安全发布对象

错误发布对象:

发布对象:使一个对象能被当前范围之外的代码所使用

对象溢出:一种错误的发布,当一个对象还没有构造完成时,就使它被其他线程所见

如何 安全 发布对象呢 ?一般采用 以下四种方式

(1)首先来看一个 非安全发布对象代码:


  
  1. @Slf4j
  2. public class UnSafePublish {
  3. private String[] states = {"a", "b", "c"};
  4. /**
  5. * 无法确保 其他的线程会通过调用此方法,来修改私有的成员变量
  6. *
  7. * @return
  8. */
  9. public String[] getStates() {
  10. return states;
  11. }
  12. public static void main(String[] args) {
  13. UnSafePublish unSafePublish = new UnSafePublish();
  14. log.info("{}", Arrays.toString(unSafePublish.getStates()));
  15. unSafePublish.getStates()[0] = "d";
  16. log.info("{}", Arrays.toString(unSafePublish.getStates()));
  17. }
  18. }

(2)非安全的 对象溢出


  
  1. public class Escape {
  2. private int thisCanBeEscape =0 ;
  3. /**一种错误的发布,当一个对象还没有构造完成时,就使它被其他线程所见*/
  4. public Escape() {
  5. new InnerClass();
  6. }
  7. private class InnerClass{
  8. public InnerClass(){
  9. log.warn("{}",Escape.this.thisCanBeEscape);
  10. }
  11. }
  12. public static void main(String[] args){
  13. new Escape();
  14. }
  15. }

 (3)单例模式的 几种方式比较

  • 懒汉模式

  
  1. /**
  2. * 懒汉模式
  3. * 单例的实例在第一次使用的时候进行创建
  4. * <p>
  5. * 在单线程的环境下,没有问题,但是在多线程的环境下就会出问题。
  6. */
  7. @NotThreadSafe
  8. @Slf4j
  9. public class SingletonExample1 {
  10. //私有构造函数
  11. private SingletonExample1() {
  12. }
  13. //单例对象
  14. private static SingletonExample1 instance = null;
  15. //静态的工厂方法
  16. //懒汉模式本身时线程不安全的,加上了synchronized关键字之后就可以实现安全
  17. //但是降低了性能,因此并不推荐这种写法
  18. public static synchronized SingletonExample1 getInstance() {
  19. if (instance == null) {
  20. instance = new SingletonExample1();
  21. }
  22. return instance;
  23. }
  24. }
  • 饿汉模式 

  
  1. /**
  2. * 饿汉模式
  3. */
  4. public class SingletonExample2 {
  5. private SingletonExample2() {
  6. }
  7. private static SingletonExample2 singletonExample2 = new SingletonExample2();
  8. public static SingletonExample2 getInstance() {
  9. return singletonExample2;
  10. }
  11. }
  •  懒汉模式+ 双重检测同步锁

  
  1. /**
  2. * 懒汉模式 -》》双重同步锁单例模式
  3. */
  4. @NotThreadSafe
  5. @Slf4j
  6. public class SingletonExample3 {
  7. //私有构造函数
  8. private SingletonExample3() {
  9. }
  10. /**
  11. * 1.分配对象的内存空间
  12. * 2.初始化对象
  13. * 3.设置instance 指向刚分配的内存
  14. * 在单线程的情况下没有问题,但是在多线程的情况下
  15. *
  16. * jvm 和cpu 优化,发生指令重排
  17. *
  18. * 1.分配对象的内存空间
  19. * 2.设置instance 指向刚分配的内存
  20. * 3.初始化对象
  21. *
  22. * 因此我们需要限制SingletonExample3类的创建的时候的指令重排,添加volatile关键字
  23. */
  24. //单例对象
  25. //volatile 加上 双重检测机制,禁止指令重排
  26. private volatile static SingletonExample3 instance = null;
  27. //静态的工厂方法
  28. public static SingletonExample3 getInstance() {
  29. if (instance == null) { //双重检测机制
  30. synchronized (SingletonExample3.class) { //同步锁
  31. if (instance == null) {
  32. instance = new SingletonExample3();
  33. }
  34. }
  35. }
  36. return instance;
  37. }
  38. }
  •  饿汉模式 (静态块的方式)

  
  1. /**
  2. * static 静态块的饿汉模式
  3. */
  4. public class SingletonExample6 {
  5. private SingletonExample6(){}
  6. private static SingletonExample6 instance =null;
  7. static {
  8. instance = new SingletonExample6();
  9. }
  10. private static SingletonExample6 getInstance(){
  11. return instance;
  12. }
  13. public static void main(String[] args){
  14. System.out.println(getInstance());
  15. System.out.println(getInstance());
  16. }
  17. }
  • 枚举模式(最推荐) 

  
  1. /**
  2. * 枚举模式,最安全
  3. * 利用枚举的特性,一个枚举的构造方法只会被调用一次实现单例模式,推荐使用这种方式
  4. * <p>
  5. * 优点:1、相比懒汉模式,更能保证线程安全性
  6. * 2、相比饿汉模式,也只会在第一次使用的时候进行创建实例,不会造成资源浪费
  7. */
  8. @ThreadSafe
  9. @Recommend
  10. public class SingletonExample7 {
  11. private SingletonExample7() {
  12. }
  13. public static SingletonExample7 getInstance() {
  14. return Singleton.INSTANCE.getInstance();
  15. }
  16. private enum Singleton {
  17. INSTANCE; //只有一个枚举变量,保证构造方法只调用一次
  18. private SingletonExample7 singletonExample7;
  19. //jvm保证这个方法绝对只调用一次
  20. Singleton() {
  21. System.out.println("我只会被调用一次");
  22. singletonExample7 = new SingletonExample7();
  23. }
  24. public SingletonExample7 getInstance() {
  25. return singletonExample7;
  26. }
  27. }
  28. public static void main(String[] args) {
  29. System.out.println(SingletonExample7.getInstance());
  30. System.out.println(SingletonExample7.getInstance());
  31. System.out.println(SingletonExample7.getInstance());
  32. }
  33. }

 

文章来源: blog.csdn.net,作者:血煞风雨城2018,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/qq_31905135/article/details/84227362

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。