这是一个简单的单例模式:
public class Singleton {
private static Singleton instance=new Singleton();
public static Singleton getInstance(){
return instance;
}
}
是不是感觉缺了一点什么?没错,Java会自动为没有明确声明构造函数的类,定义一个public的无惨数的构造函数,所以上面的例子并不能保证被其他对象创建出来,别人完全可以直接"new Singleton()"
所以单例模式比较重要的代码就是一个private的构造函数。
//改进后的版本,采用懒加载
public class Singleton {
private static Singleton instance=null;
//重要代码
private Singleton(){}
public static Singleton getInstance(){
if (instance==null){
instance=new Singleton();
}
return instance;
}
}
如果在单线程环境下上面这个单例模式还顶得住,但是如果处于并发场景,就需要考虑线程安全了。
双检锁单例:
public class Singleton {
private static volatile Singleton instance=null;
//重要代码
private Singleton(){}
public static Singleton getInstance(){
if (instance==null){//尽量避免重复进入同步快
synchronized (Singleton.class){
if (instance==null){
instance=new Singleton();
}
}
}
return instance;
}
}
- 这里的volatile能够提供可见性即禁用缓存,以及保证getInstance返回的是初始化完全的对象
- 在同步之前进行null检查,以尽量避免进入相对耗时的同步快
- 直接在class级别进行同步,保证getSingleton()方法在多个线程安全调用。
静态内部类单例模式,和双检锁单例模式一样都能保证线程安全。
public class StaticSingleton {
private StaticSingleton(){}
public static StaticSingleton getInstance(){
return Holder.staticSingleton;
}
private static class Holder{
private static StaticSingleton staticSingleton=new StaticSingleton();
}
}