引子
开发中很多对象哦我们只需要一个,比方说:线程池,缓存,对话框,注册表对象等。如果制造出多个实例,会导致许多问题产生。没错,这就是单例模式,相信大家或多或少都听说过单例模式。
定义
确保一个类只有一个实例,并提供一个全局的访问点。
单例模式只有一个一个类,听起来很简单,但是实现起来会有很多问题。
尝试1
延迟实例化:
public class Singleton {
private static Singleton uniqueInstance;
//私有化构造
private Singleton(){}
public static Singleton getInstance(){
//判断是否创建
if(uniqueInstance==null){
uniqueInstance=new Singleton();
}
//返回
return uniqueInstance;
}
}
1.完成了私有化构造器
2.判断单例是否创建
3.取出单利
好处:和全局变量一样,多了个优点:单件可以延迟实例化。
问题:产生问题,用多线程模拟出错误。
尝试2
解决方法,用同步关键字:
public class Singleton {
private static Singleton uniqueInstance;
//私有化构造
private Singleton(){}
//加入同步
public static synchronized Singleton getInstance(){
//判断是否创建
if(uniqueInstance==null){
uniqueInstance=new Singleton();
}
//返回
return uniqueInstance;
}
}
优点:解决了多线程产生的问题
缺点:只需要第一次同步,和直接用同步会降低性能,当创建好对象后,每次调用这个方法,同步都是一种累赘。
那到底应该用哪种方法来解决存在的问题呢?让我们看看我们有几种选择?
改善多线程的几种选择:
1.这个getInstance()的同步性能对应用程序不是很关键
这种情况意味着我们的程序里使用getInstance()的地方很少,或者是你不在乎同步关键字产生的效率问题,那么就直接使用有同步关键字的单例吧。
2.使用“急切”创建实例,而不用延迟实例化的做法
如果程序总是使用或创建单例,或者程序创建或运行不太繁重,那么你可以使用“急切”地创建实例。
public class Singleton {
//在程序开始的时创建
private static Singleton uniqueInstance=new Singleton();;
//私有化构造
private Singleton(){}
public static Singleton getInstance(){
//返回
return uniqueInstance;
}
}
这个方法以来jvm加载类的时候创建静态变量,使用时确保是单例。
3.双重检查加锁,确保getInance()同步使用的次数
public class Singleton {
//volatile确保多个线程正确处理
private static volatile Singleton uniqueInstance;
// 私有化构造
private Singleton() {
}
public Singleton getInstance() {
// 判断是否创建
if (uniqueInstance == null) {
synchronized (Singleton.class) {
//双重判断
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
// 返回
return uniqueInstance;
}
}
这种方法可以对比第一种方法,增加了很多性能,应为除了第一个创建是同步外,后面的都不是同步的。但是注意volatile 关键字是java 1.5才出现的,所以1.4以及以前的不能使用volatile 。
所以当我们使用单例模式一定要小心加小心,根据自己程序的实际情况来选着哪一种实现方式。