概述
单例模式是设计模式中最简单的模式了,它的目的是为了保证一个流程中只有一个对象存在,相当于一个全局变量。
1 单例模式的实现
创建一个类,调用者不能通过默认构造方法的方式创建实例,而是提供一个接口用来返回唯一的实例。
public class SingleInstance{
private static SingleInstance instance = null;
private SingleInstance(){}
public static SingleInstance getInstance(){
if(instance == null){
instance = new SingleInstance();
}
return instance;
}
}
2 同步单例模式的实现
1中是最简单的单例模式,但是在多线程状态下就出现问题了,如果线程A调用getInstance()方法时,开始先判断instance是否为空,如果为空则需要创建实例,但是此时A线程阻塞,B线程也调用了getInstance()方法,也发现Instance为空,所以需要创建实例,此时A线程继续执行,则又创建了一个实例,A和B线程各创建了一个实例对象,违背了单例模式的初衷,所以需要实现单例模式的线程同步。
public class SingleInstance{
private static SingleInstance instance = null;
private SingleInstance(){}
public synchronized static SingleInstance getInstance(){
if(instance == null){
instance = new SingleInstance();
}
return instance;
}
}
3 提高单例模式的性能
2中的单例模式保证了线程的同步问题,但是也存在着问题,那就是性能问题,采用synchronized关键字来回对方法加锁有很大的性能开销,那么能否只对某个对象加锁呢,答案是可以的。去掉方法同步的关键字synchronized,对SingleInstance.class进行加锁操作,代码可如下:
public class SingleInstance{
private static SingleInstance instance = null;
private SingleInstance(){}
public static SingleInstance getInstance(){
synchronized(SingleInstance.class){
if(instance == null){
instance = new SingleInstance();
}
}
return instance;
}
}
接下来的问题是当多个线程同时获取实例时,依然要对某个对象进行同步操作,有没有更好的办法呢,答案是有的,那就是在同步之前先判断Instance是否为空,如果已经是非空了,也就没必要同步了,那么可以改成如下的代码,如下所示:
public class SingleInstance{
private static SingleInstance instance = null;
private SingleInstance(){}
public static SingleInstance getInstance(){
if(instance == null){
synchronized(SingleInstance.class){
if(instance == null){
instance = new SingleInstance();
}
}
}
return instance;
}
}
看似没有任何问题了,其实不然,主要问题在于instance = new SingleInstance()这行代码并不是原子性的,也就是说,这行代码需要处理器分为多步才能完成,其中主要包含两个操作,分配内存空间,引用变量指向内存,由于编译器可能会产生指令重排序的优化操作,所以两个步骤不能确定实际的先后顺序,假如线程A已经指向了内存,但是并没有分配空间,线程A阻塞,那么当线程B执行时,会发现Instance已经非空了,那么这时返回的Instance变量实际上还没有分配内存,显然是错误的。
4 单例模式中的volatile
volatile是Java提供的关键字,它具有可见性和有序性,被volatile修饰的写变量不能和之前的读写代码调整,读变量不能和之后的读写代码调整,所以,只要把instance加上volatile关键字就可以避免3中的问题了。代码如下所示:
public class SingleInstance{
private static volatile SingleInstance instance = null;
private SingleInstance(){}
public static SingleInstance getInstance(){
if(instance == null){
synchronized(SingleInstance.class){
if(instance == null){
instance = new SingleInstance();
}
}
}
return instance;
}
}
最后
以上就是感动小蚂蚁为你收集整理的单例模式中的double check的全部内容,希望文章能够帮你解决单例模式中的double check所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复