传统的单例模式大致可以分为饿汉式与懒汉式两种形式,其区别为:
- 饿汉式会提前将该类创建好
- 懒汉式在第一次调用的时候创建
但是传统的单例模式在多线程下是有线程安全问题的,在方法体上采用synchronized虽然可以解决问题,但是过于笨重,因此通常采用双重校验锁来保证线程安全。
public class SingletonDemo {
public static void main(String[] args) {
//并发1000个线程查看效果
for (int i = 0; i < 1000; i++) {
new Thread(()->{
Singleton.getInstance();
}).start();
}
}
}
class Singleton{
//volatile关键字需要加上,因为创建对象在底层可能会出现指令重排问题而导致单例失效,虽然出现的机率比较低
private static volatile Singleton instance = null;
private Singleton(){
//对象被创建的时候将会输出
System.out.println(Thread.currentThread().getName()+"new了");
}
//创建实例
public static Singleton getInstance(){
if(instance == null){
synchronized (Singleton.class){
if(instance == null){
return instance = new Singleton();
}
}
}
return instance;
}
}
程序执行结果
发现1000个线程并发执行时,对象只被创建了一次。
注:双重校验锁单例模式还是可以通过反射来破坏,可以采用enum来创建单例模式,枚举模式无法通过反射创建