单例模式(懒汉式)
在懒汉式写法中, 我们需要非常注意线程同步的问题. 大概有一下几个:
1. getInstance() 直接锁方法好不好
2. 双重锁定
3. synchronized(this)行不行
1. getInstance() 直接锁方法好不好
这种写法:
class Singleton {
private static Singleton instance;
private Singleton(){}
public static synchronized Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
我们可以看到这里synchronized是锁方法, 当两个线程都要进入getInstance()时, 只有一个能进入, 并创建出实例, 然后另外一个进入后, 判断 instace不为null, 然后直接得到instance. 这种做法是没有错误的. 但是由于线程都需要通过getInstance()来获取对象, 所以getInstance()调用频率很高, 所以线程被锁的频率也很高, 所以这种做法效率低.
2. 双重锁定
由于上面效率的原因, 你可能就会想到把 syschronized 放在 getInstance()里面, 这种可避免在调用getInstance()时的阻塞问题, 如下:
class Singleton {
private static Singleton instance;
private Singleton(){}
public static Singleton getInstance(){
if(instance == null){
synchronized(Singleton.class){
instance = new Singleton();
}
}
return instance;
}
}
这种写法看似没有问题, 其实却有一个很大的隐患, 在于: 如果两个线程同时执行getInstance(),判断 instance都不为null后, 进入if判断语句. 这个时候一个线程获得锁, 然后进入new了一个对象, 并开心的执行完了. 这个时候另外一个线程获得了锁, 但让它也不会再去判断 instace是否为null, 所以它也会再执行一次new操作. 所以这里执行了两次new操作. 当然最后instance还是只指向后一次new的对象.
所以这个时候需要双重锁定, 就是在 synchronized中再加一次 null判断, 如下:
class Singleton {
private static Singleton instance;
private Singleton(){}
public static Singleton getInstance(){
if(instance == null){
synchronized(Singleton.class){
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
这样就可以保证不会new两次, 也是相对比较正确的, 并且效率也很高.
3. synchronized(this)行不行
答案是不行的, 如果你写代码看一看, 直接就提示语法错误了, 因为我们的 getInstance() 方法是 static的, 所以里面不能使用 this.
好了以上三点终结, 希望对大家有帮助.