当不用考虑线程安全时,使用传统方法可以很容易解决,这里我们在考虑线程安全性的情况下实现单例模式
1. 双检锁
这是懒加载方式
public class Singleton {
private static volatile Singleton INSTANCE;
private Singleton(){}
public static Singleton getInstance(){
if(INSTANCE == null){
synchronized(Singleton.class){
if(INSTANCE == null){
INSTANCE = new Singleton();
}
}
}
return INSTANCE;
}
}
注意
- volatile是必须的,因其保证可见性
- 第二次检查防止的情况是:多个线程都通过了第一个检查,而第一个获得锁的线程在初始化之后,其后面的线程就可以在第二个检查前止步.
性能分析
只有在第一次初始化之后由于锁的缘故,性能低了点,但此后每次执行第一个if都转到return语句,性能比第一次好了挺多
2. 静态工厂方法
这是饿汉式
public class Singleton{
private static final Singleton INSTANCE = new Singleton();
private Singleton(){}
public static Singleton getSingleton(){
return INSTANCE;
}
}
分析:
当类第一次被加载到内存它才实例化,jvm会保证初始化过程的线程安全性
3. 枚举单例
这是懒加载方式
public enum Singleton {
INSTANCE;
private Singleton() {}
}
或许这是最简单最安全的方式了,其线程安全性由JVM保证,而且枚举天生保证序列化单例,对于反射攻击也可以保证安全,同时也没有性能缺陷
4. 静态内部类
这是懒加载方式
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
分析:
SingletonHolder隐藏在内部不会被外部了解,这种方式没有性能缺陷
欢迎访问我的 个人网站(主要), Github, CSDN(主要), 博客园, 简书, 掘金, 知乎, 微信公众号:HelloVant(主要)