JAVA中的Singleton模式

单例模式,顾名思义,只能有一个实例。

一.从多线程安全说起,如下图代码,此问题可以用synchronized关键字来解决。该方法缺点:每一个线程在获取实例对象之前都要在synchronized上同步的对象上进行等待,因此效率不高。

 

 

二.Double Check方法,见下图代码。Double Check的初衷是只有当instance为NULL时执行的线程才需要在synchronized同步的对象上等待,这避免了“一”方法中的每个线程在获得实例对象之前均要在synchronized同步的对象上进行等待的弊端。但是这一设想在JAVA中却不适应。原因:JAVA内存模型并不保证一个对象的引用只有在它构造完之后才被赋予一个实例。例如:A线程执行到了instance=new SingletonClass();"instance=new SingletonClass()"这一过程的执行步骤可能是下述情形:第一步,JVM分配内存;第二部,instance指向分配的内存;第三步,调用构造方法。假设此时A线程执行到了第二步,而同时B线程开始执行,此时B线程检测到的instance不为null,但因为A线程中还未执行第三步即还没调用构造函数,所以B线程中返回的instance是不正确的。当然,这种错误时可能发生的,尽管下面代码中的执行得到的结果是正确的。

 

三.解决方法2中出现的问题主要有两种方法:

(1)使用静态内部类。好处:1.可以实现延时实例化。即只有当类调用getInstance()方法时才会对instance进行实例化,而“一”“二”两种方法中都是在类第一次加载时便对instance进行了实例化。2.解决了“一”方法中,每个线程在获得实例对象之前都要在synchronized同步的对象上进行等待的缺陷。

 

 

 

 (2)在变量前加上volatial关键字可以屏蔽掉编译器优化。

编译器的优化:Java内存模型中,线程可以把变量保存在寄存器中,而不是直接在主存中进行读写。这可能造成一个线程在主存中修改了一个变量的值,而另外一个线程还继续使用它在寄存器中的变量值的拷贝,造成数据的不一致。

volatial关键字告诉JVM,这个变量是不稳定的,每次使用它都到主存中进行读取。

依据java语言描述:除了long和double类型外,对其他基本变量的读与写操作均是原子操作。在本例中,对instance的构造操作并非原子操作,所以可能会出产生double check方法中出现的问题,如果是换做对除long和double外的其他原子类型操作则视具体情况可以不用volatial关键字进行修饰。

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值