单例模式
来源:互联网 发布:本地端口1080 编辑:程序博客网 时间:2024/04/30 06:19
单例模式常见的三种实现方式:
1.懒汉式
为什么称之为懒汉式,因为这种方式很“懒”,只有当别人向它请求一个对象的时候,它才会产生一个对象供别人使用:
package DesignMode;public class SingletonMode{ private static SingletonMode single = null; public static SingletonMode getInstance() { if(single == null) { single = new SingletonMode(); return single; }else{ return single; } }}
以上代码有个问题,那就是在多线程的情况下仍然有可能会产生多个实例,因此就有如下改进:
①:改进一
package DesignMode;public class SingletonMode{ private static SingletonMode single = null; //方法上加synchronized关键字 public static synchronized SingletonMode getInstance() { if(single == null) { single = new SingletonMode(); return single; }else{ return single; } }}
加了synchronized关键字防止线程并发引发产生多个实例。但是这样会产生2个问题,一个就是性能瓶颈问题:每次获得对象实例的时候都要对字节码加锁,从而影响程序性能;第二个问题:我们称第二个问题为“红色巨人”(这个昵称是我自己起的…后面我们会再次提到这个问题,我会解释他)。
首先为了解决上述问题,我们产生了改进型二。
②:改进二
package DesignMode;public class SingletonMode{ private static SingletonMode single = null; public static SingletonMode getInstance() { if (single == null) { //锁的范围缩小 synchronized (SingletonMode.class) { if (single == null) { single = new SingletonMode(); } } } return single; }}
如上优化之后,在并发环境下,某些线程就会不必进入同步块,因此省去了加锁的性能开销。但是我们要注意,“改进二”的优化是错误的!我们上面提到过“红色巨人”这个问题,关键就在这里:
下面是针对红色巨人问题的改进:
③:改进三
package DesignMode;public class SingletonMode{ private static volatile SingletonMode single = null; public static SingletonMode getInstance() { if (single == null) { //锁的范围缩小 synchronized (SingletonMode.class) { if (single == null) { single = new SingletonMode(); } } } return single; }}
这里我们只是加了一个volatile关键字。
下面我来解释一下为什么需要加volatile关键字。
首先我来简要说一下volatile关键字的作用,volatile可以保证变量的内存可见性,具体是通过两种方式保证的(加入内存屏障和禁止重排序优化)。具体可以参考JAVA并发机制的底层实现原理。
我们知道,在JVM装载类的时候,第三个阶段,也就是准备阶段(具体可以参考我的这篇博客),会将申请到的内存空间进行初始化,具体可以用下面的三行伪代码进行解释:
memory = allocate(); //1.分配对象内存空间ctorInstance(memory); //2.初始化这块空间instance = memory; //3.设置instance指向刚刚分配的这块地址
但是在某些(JIT编译器上),可能会发生重排序,排序之后如下:
memory = allocate(); //1.分配对象内存空间instance = memory; //2.设置instance指向刚刚分配的这块地址ctorInstance(memory); //3..初始化这块空间
假设重排序之后如上,当执行完第2步之后,如果恰好有另外一个线程请求单例对象,那么对这个对象的检测肯定不会为null,因此会返回一个instance对象,但是instance对象指向的内存空间还未执行第三步,即未初始化,因此如果该线程继续使用这个instance对象,就会发生问题。
- 单例、单例模式
- 单例模式-多线程单例模式
- 单件模式(单例模式)
- 设计模式------单例模式
- 设计模式------单例模式
- 设计模式-单例模式
- 设计模式 - 单例模式
- 设计模式---单例模式
- 设计模式---单例模式
- PHP模式-单例模式
- 【设计模式】单例模式
- 设计模式-单例模式
- 设计模式----单例模式
- 设计模式--单例模式
- 设计模式-单例模式
- 单例模式(单子模式)
- 设计模式-单例模式
- [设计模式] 单例模式
- php借助mcript扩展实现对称加密
- Area poj 1654 计算几何
- Solr Facet.
- 【Laravel Excel译文】——导出
- coremail批量删除指定用户的邮件
- 单例模式
- JAVA学习随笔6
- iOS 在闲置一段时间后执行指定动作
- 自写聊天室_LinuxC实现(4)——项目文档
- 比赛
- 如何将1万元用到极致?5种方法效果截然不同
- style、theme的关系与使用
- uva11300分金币
- 2016年最新前端开发面试题(面霸题库)