线程安全的单例模式
单例模式是最简单的设计模式,但是使用时要注意线程安全问题,以下是单例模式的几种写法,比较好的方法是基于类初始化的方式,既能实现线程安全,又可以实现延迟加载。饿汉模式可实现线程安全,但是效率可能会出现问题。还应注意双重锁的检测,由于指令重排并不能保证线程安全
一.饿汉式:
public class Singleton{
private final static Singleton instance=new Singleton();//无论用不用,类加载时都会new
private Singleton(){}//必须是private 的,保证用户不能手动new 一个实例
public Singleton getInstance(){
return instance;
}
}//线程安全,因为static 的变量一个类只有一份
二.懒汉式:
1.public class Singleton{
private static Singleton instance=null;
private Singleton(){}
public static Singleton getInstance(){
if(instance==null)
instance=new Singleton();
return instance;
}
}
第一种方法适用于单线程,非线程安全。 static关键字的用法,使用static关键字修饰的变量只有在第一次使用的时候才会被初始化,而且一个类里面static的成员变量只会有一份,这样就保证了无论多少个线程同时访问,所拿到的Resource对象都是同一个。
2.public class Singleton{
private static Singleton instance=null;
private Singleton(){}
public static synchronized Singleton getInstance(){//synchronized修饰,表示同一时间只有一个线程能进入该方法
if(instance==null)
instance=new Singleton();
return instance;
}
}
第二种方法线程安全,但是锁粒度过大,运行效率低
3.public class Singleton(){
private static Singleton instance=null;
private Singleton(){}
public static Singleton getInstance(){
if(instance==null)
synchronized(Singleton.class)
{
if(instance==null)//判断两次空
instance=new Singleton();
}
return instance;
}
}
第三种方法降低了锁的粒度,采用了双重锁检测的方式,但是由于指令重排的存在,所以非线程安全
有数据依赖性的两个操作不会被重排序,但是当这两个操作在不同的线城时,数据依赖性不被考虑
4.public class Singleton{
private static volatile Singleton instance=null;//用volatile来修饰
private Singleton(){}
public static Singleton getInstance(){
if(instance==null){
synchronized(Singleton.class){
if(instance==null)
instance=new Singleton();
}
}
return instance;
}
}
第四种方法用volatile来修饰instance,volatile的作用:保证内存可见性,防止指令重排
5.public class InstanceFactory{
private static class InstanceHolder{
public static Instance instance=new Instance();
}
public static getInstance(){
return InstanceFactory.InstanceHolder.instance;
}
static Instance(){
}
}

浙公网安备 33010602011771号