• java线程安全(单例模式)(转载)


    原文链接:http://www.jameswxx.com/java/%E8%AF%B4%E8%AF%B4%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F/

    单例模式?多么简单!也许吧,可是要通过简单的现象,看到问题的本质,就比较难,知其然而不知其所以然,这种态度不好。

    一:看看最简单的

    1 public class SingleInstance{  
    2   private static  instance=new SinleInstance();  
    3   
    4   public static SingleInstance getInstance(){  
    5    return instance;  
    6   }  
    7 }

    这个很明了,也确实会返回唯一的实例,但是如果我永远都不会用到SingleInstance.getInstance(),instance这个对象却一直存在,占用了内存空间,浪费。

    二:那就不先实例化

     1 public class SingleInstance{  
     2   private static  SingleInstance instance;  
     3   
     4   public static  SingleInstance getInstance(){  
     5    if(instance==null){  
     6       instance=new SingleInstance();  
     7    }  
     8    return instance;  
     9   }  
    10 } 

    表面上,这个似乎是可行的。但是很显然,在多线程并发环境中,可能会创建两个instance,也有可能一个线程拿到的instance是一个不完整的实例。

    三:好吧,那我加上同步总可以吧

     1 public class SingleInstance{  
     2   private static  SingleInstance instance;  
     3   
     4   public static synchronized SingleInstance getInstance(){  
     5    if(instance==null){  
     6       instance=new SingleInstance();  
     7    }  
     8    return instance;  
     9   }  
    10 }

    这个虽然不会有内存上的浪费,但是有同步锁住了整个class,会降低系统的性能。按照数据结构的说法,就是一个提高了空间复杂度,一个提高了时间复杂度。

    四:最佳实践

    比较好的做法  

    1 public class SingleInstance {  
    2     private static class InstanceHolder {  
    3         public static final SingleInstance instance = new SingleInstance();  
    4     }  
    5   
    6     public static SingleInstance getInstance() {  
    7         return InstanceHolder.instance;  
    8     }  
    9 }

    这种Holder做法保证了实例在用到的时候才会创建,而且创建的实例肯定是唯一的。


    五:所谓的DCL 
    下面这种做法是广为流传的所谓DCL(双重检查锁定)做法,这是没有正确理解java内存模型造成的,只保证了创建实例的原子性,而没有解决共享资源的可见性。

     1 public class SingleInstance{  
     2   private static  SingleInstance instance;  
     3   
     4   public static  SingleInstance getInstance(){  
     5    if(instance==null){  
     6        synchronized(SingleInstance.class){  
     7            if(instance==null){  
     8                instance=new SingleInstance();  
     9            }  
    10        }  
    11    }  
    12    return instance;  
    13   }  
    14 }

    表面上看,这个似乎确实没有什么问题呢,其实还是有问题的,虽然概率比较小,要深刻的理解为什么,必须要对java内存模型比较熟悉。对于instance的创建,某个时刻某个线程拿到了同步锁,将instance创建了,并且及时写回了主存。但是对于另一个线程而言,它不能及时“看到”instance变量的最新值。它的instance可能是工作内存里的而不是主内存里的,甚至更为糟糕的情况是,instance是主内存的,可它的某些属性是工作内存的,这会导致程序发生莫名其妙不可捉摸的错误。在平台级框架里,这会造成系统在高并发环境下不稳定,甚至造成致命的错误 。

  • 相关阅读:
    【转】c#基础系列1---深入理解值类型和引用类型
    【转】Aspnet Core为什么支持跨平台
    [翻译svg教程]svg学习系列 开篇
    使用docker 解决一个小问题,你也可能用的到
    增加软链接
    漫长的表白
    被社会抽了一巴掌
    杂乱五章的2015年终总结
    [资源分享]yslow 与firebug 修复版本Firefox35【绿色版本下载】
    Web前端性能测试-性能测试知多少---深入分析前端站点的性能
  • 原文地址:https://www.cnblogs.com/peak-c/p/6558162.html
Copyright © 2020-2023  润新知