单例模式主要解决的是,一个全局使用的类频繁的创建和消费,从而提升提升整体的代码的性能。
单例模式原则
- 私有构造。(阻止类被常规方法实例化)
- 以静态方法或者枚举返回实例。(保证实例的唯一性)
- 确保实例只有一个,尤其是多线程环境。
- 确保反序列化时不会重新构建对象。
懒汉模式(线程安全)
在初次调用时构建实例 (双重检查)。
锁不加在方法上,因为如果加在方法上,多线程访问时只有一个线程能执行该方法。
在synchronized 代码块中再次检查实例是否被创建,可能同时有两个线程A和B都到达了synchronized 代码块前,A获得了锁,执行了实例的初次创建。A释放锁后,B获得锁,若不进行double check,实例将会重复创建。
public class Singleton_02 {
private static Singleton_02 instance;
private Singleton_02() {
}
public static Singleton_02 getInstance(){
if (null != instance) return instance;
synchronized (Singleton_02.class){
if (null != instance) return instance;
instance = new Singleton_02();
return instance;
}
}
}
饿汉模式(线程安全)
public class Singleton_03 {
private static Singleton_03 instance = new Singleton_03();
private Singleton_03() {
}
public static Singleton_03 getInstance() {
return instance;
}
}
instance 在类加载时被创建,类加载过程是线程安全的。
使用类的内部类(线程安全)
public class Singleton_04 {
private static class SingletonHolder {
private static Singleton_04 instance = new Singleton_04();
}
private Singleton_04() {
}
public static Singleton_04 getInstance() {
return SingletonHolder.instance;
}
}
既保证了线程安全又保证了懒加载,同时不会因为加锁的方式耗费性能。因为JVM虚拟机可以保证多线程并发访问的正确性,也就是一个类的构造方法在多线程环境下可以被正确的加载。
CAS(线程安全)
public class Singleton_06 {
private static final AtomicReference<Singleton_06> INSTANCE = new AtomicReference<Singleton_06>();
private Singleton_06() {
}
public static final Singleton_06 getInstance() {
for (; ; ) {
Singleton_06 instance = INSTANCE.get();
if (null != instance) return instance;
INSTANCE.compareAndSet(null, new Singleton_06());
return INSTANCE.get();
}
}
public static void main(String[] args) {
System.out.println(Singleton_06.getInstance()); // org.itstack.demo.design.Singleton_06@2b193f2d
System.out.println(Singleton_06.getInstance()); // org.itstack.demo.design.Singleton_06@2b193f2d
}
}