单例模式《漫谈设计模式》阅读笔记
单例模式:
如果要保证系统里一个类最多只能存在一个实例时,我们就需要用单例模式。这种情况在我们应用中经常碰到,例如缓存池,数据库连接池,线程池,一些应用服务实例等。
最简单的单例:
Public class Singleton{
Private static Singleton instance = new Singleton();
Private Singleton();
Public static Singleton getInstance(){
Return instance;
}
}
此实现是线程安全的,使用也非常简单:Singleton singleton=Singleton.getInstance();
延迟创建:
Public class UnTreadSafeSingleton{
Private static Singleton instance = new Singleton();
Private Singleton();
Public static UnTreadSafeSingleton getInstance(){
if(instance==null){
Instance=new UnTreadSafeSingleton();
}
return instance;
}
}
上述实现不是线程安全的,为了达到线程安全可以在获取实例的方法上加上关键字synchroniezd。但是在多线程高并发访问的情况下,给方法加上synchroniezd关键字会使性能大不如前。我们仔细分析一下不难发现,使用synchroniezd关键字对整个getInstance()方法进行同步是没有必要的:我们只要保证实例化这个对象的那段代码被一个线程执行就可以了,而返回引用的那段代码是木有必要同步的。按照这个想法,大致代码如下:
Public class DoubleCheckSingleton{
Private volatile static DoubleCheckSingleton instance=null;
//constructors
Public static DoubleCheckSingleton getInstance(){
if(instance==null){
Synchronized(DoubleCheckSingleton.class){
if(instance==null)
Instance=new DoubleCheckSingleton();
}
}
return instance;
}
}
在getInstance()方法里,我们首先判断此实例是否已经被创建,如果还没有创建,首先使用synchronized同步实例化代码块。在同步代码块里,我们还需要再次检查是否已经创建了此类的实例,这是因为:如果没有第二次检查,这时有两个线程A和B同时进入该方法,它们都监测到instance为null,不管哪一个线程先占据同步锁创建实例,都不会阻止另一个线程继续进入实例化代码重新创建实例对象。
属性instance是被volatile修饰的,因为volatile具有synchroniezd的可见性特点,也就是说线程能够自动发现volatile变量的最新值。这样,如果instance实例化成功,其他线程便能立即发现。