设计模式之单例模式
单例模式(Singleton),也成单件模式,其含义是保证一个类仅有一个实例,并提供一个访问它的全局访问点。因此实现单例模式有三个要求,第一是程序当中只有一个实例,不会再创建第二个, 第二这个唯一实例必须由自己创建,第三这个实例提供全局访问点。
单例模式在开发中使用较多,而且很多的框架中也常使用该模式,如我们常见的windows任务管理器等,其适用性:
当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时。
当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时。
单例模式常见有两种使用方式,一个是懒汉式,另一个是饿汉式,其实就是何时创建实例的问题,前者使用了延迟实例化,在使用时创建实例。
饿汉式如下:
private Singleton() {}
private static final Singleton singleton = new Singleton();
public static Singleton getInstance() {
return singleton;
}
}
懒汉式如下:
private Singleton() {}
private static Singleton singleton=null;
public synchronized static Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
单例模式讲到这里本该结束了,但是在大家使用上述的懒汉式方式时在多线程程序中,出现多不一致的情况,网上有很多方法。在此介绍三种,如果单纯的加上synchronized关键字,同步问题是解决了,但是出现了效率低的问题:
public static synchronized Singleton getInstance() {
instance = new Singleton();
}
return instance;
}
大家在使用时多用的是双重检查的方式,就是在instance=new Singleton()这句,由于不是原子操作会有同步问题,因此如下:
public static Singleton getInstance() {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
然后该方式也并不保证完全没有同步问题存在,java推荐在声明intance时,加上volatile关键字,然而这样代码反而复杂了。
第二种方式是用内部类的形式,类似与饿汉式结合,如下 :
public class Singleton{
private static class SingletonHolder {
static final Singleton singleton = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.singleton;
}
}
该方式能保证线程安全问题,而且没有性能缺陷,使用时不妨试试。
第三种方式是采用加互斥锁来实现线程安全问题,其采用了jdk中 java.util.concurrent.locks包下的类来实现,可参考设计模式从入门到精通 ,该书在该节讲解的非常详细,本人比较推崇,在此不再介绍。