Java设计模式:单例设计模式
单例设计模式:解决一个类在内存中只存在一个对象,单例设计模式主要有两种实现方式:懒汉式,饿汉式。
1.为了保证只有一个对象,先禁止其他程序创建该类对象。
2.为了保证其他程序能访问该类对象,只好在本类中先创建好该类的一个对象。
3.对外提供一个其他程序访问该对象的方式。
什么是线程安全?
如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。
或者说:一个类或者程序所提供的接口对于线程来说是原子操作,或者多个线程之间的切换不会导致该接口的执行结果存在二义性,也就是说我们不用考虑同步的问题,那就是线程安全的。
一:懒汉式单例
public class Singleton {
//创建一个该类的实例
private static Singleton s = null;
//将构造方法私有化,避免了类被外界实例化
private Singleton(){}
//当该方法被使用的时候才去创建该类的实例
public static Singleton getInstance(){
if(s==null){
s = new Singleton();
}
return s;
}
}
上述代码如果多线程访问会出现安全隐患,内存中可能出现多个Singleton类的实例化对象,若想保证线程安全,则需对getInstance方法进行改造。这种改造分为三种方式。
1.在getInstance方法上加上同步
public static synchronized Singleton getInstance(){
if(s==null){
s = new Singleton();
}
return s;
}
此种方式可以实现多个线程并发访问getInstance方法时,线程的安全性,当一个线程访问getInstance时,该线程对该方法加锁,别的线程暂时无法访问。缺点:任意一个线程若要拿到Singleton 对象的实例都要判断锁,线程比较多的时候会比较低效。
2.双重检查锁定
public static Singleton getInstance(){
if(s==null){
synchronized(Singleton.class){
if(s==null){
s = new Singleton();
}
}
}
return s;
}
在getInstance中做了两次null检查,确保了只有第一次调用单例的时候才会做同步,这样也是线程安全的,同时避免了每次都同步的性能损耗。
3.静态内部类
public class Instance {
private static class LazyHolder{
private static final Instance INSTANCE = new Instance();
}
private Inner(){};
public static final Instance getInstance(){
return LazyHolder.INSTANCE;
}
}
当getInstance方法第一次被调用的时候,它第一次读取LazyHolder.instance,内部类LazyHolder类得到初始化;而这个类在装载并被初始化的时候,会初始化它的静态域,从而创建Instance的实例,由于是静态的域,因此只会在虚拟机装载类的时候初始化一次,并由虚拟机来保证它的线程安全性。
二.饿汉式单例
public class Single {
private static final Single s = new Single();
private Single(){}
public static Single getInstance(){
return s;
}
}
饿汉式在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变,所以天生是线程安全的。

浙公网安备 33010602011771号