1、简介
单例模式(Singleton Pattern)是Java中最简单的设计模式之一,主要保证一个类只有一个实例,同时单例模式不允许外部创建,所以该类需要创建自己的唯一实例并且提供一个全局访问的方式,单例模式主要解决全局使用的类对象频繁创建和销毁的问题来提升整体的代码性能。
2、单例模式的七种实现方式
2.1、懒汉式(线程不安全)
public class SingletonLazyThreadFalse {
private static SingletonLazyThreadFalse singletonLazyThreadFalse;
private SingletonLazyThreadFalse() {
}
public static SingletonLazyThreadFalse getInstance() {
if (null == singletonLazyThreadFalse) {
singletonLazyThreadFalse = new SingletonLazyThreadFalse();
}
return singletonLazyThreadFalse;
}
}
- 此种方式是懒加载,但是并发情况下出现多个线程访问时会造成创建多个实例的问题,所以严格意义上来说并没有达到单例的要求。
2.2、懒汉式(线程安全)
public class SingletonLazyThreadTrue {
private static SingletonLazyThreadTrue singletonLazyThreadTrue;
private SingletonLazyThreadTrue() {
}
public static synchronized SingletonLazyThreadTrue getInstance() {
if (null == singletonLazyThreadTrue) {
singletonLazyThreadTrue = new SingletonLazyThreadTrue();
}
return singletonLazyThreadTrue;
}
}
- 此种方式通过给获取实例的方法加锁保证线程安全,但是所有的访问都需要锁占用从而导致资源的浪费,会影响效率。
2.3、饿汉式(线程安全)
public class SingletonHungryThreadTrue {
private static SingletonHungryThreadTrue singletonHungryThreadTrue = new SingletonHungryThreadTrue();
private SingletonHungryThreadTrue() {
}
public static SingletonHungryThreadTrue getInstance() {
return singletonHungryThreadTrue;
}
}
- 此种方式没有加锁,执行效率比较高,但是实例对象时在程序启动的时候就实例化了,容易产生垃圾对象,浪费内存。
2.4、静态内部类/登记式(线程安全)
public class SingletonInternalThreadTrue {
private static class SingletonHolder {
private static SingletonInternalThreadTrue singletonInternalThreadTrue = new SingletonInternalThreadTrue();
}
private SingletonInternalThreadTrue() {
}
public static SingletonInternalThreadTrue getInstance() {
return SingletonHolder.singletonInternalThreadTrue;
}
}
- 此种方式使用内部静态类实现,通过显示调用getInstance() 方式来加载SingletonHolder从而达到懒加载的目的,即保证了线程安全同时又不会因为加锁的方式耗费性能。
2.5双重锁校验(线程安全)
public class SingletonCheckLockThreadTrue {
private static SingletonCheckLockThreadTrue singletonCheckLockThreadTrue;
private SingletonCheckLockThreadTrue() {
}
public static SingletonCheckLockThreadTrue getInstance() {
if (null == singletonCheckLockThreadTrue) {
synchronized (SingletonCheckLockThreadTrue.class) {
if (null == singletonCheckLockThreadTrue) {
singletonCheckLockThreadTrue = new SingletonCheckLockThreadTrue();
}
}
}
return singletonCheckLockThreadTrue;
}
}
- 此种方式是方法级锁的优化,通过双锁机制减少部分获取实例的耗时来提高性能。
2.6、CAS[AtomicReference](线程安全)
public class SingletonCASThreadTrue {
private static final AtomicReference<SingletonCASThreadTrue> reference = new AtomicReference<SingletonCASThreadTrue>();
private static SingletonCASThreadTrue singletonCASThreadTrue;
private SingletonCASThreadTrue() {
}
public static SingletonCASThreadTrue getInstance() {
for (;;) {
singletonCASThreadTrue = reference.get();
if (null == singletonCASThreadTrue) {
reference.compareAndSet(null, new SingletonCASThreadTrue());
}
return reference.get();
}
}
}
- 此种方式通过Java并发库的AtomicReference来保证线程安全,依赖与CAS的忙等算法来保证线程安全可以支持较大的并发性。
2.7、枚举单例(线程安全)
public enum SingletonEnumThreadTrue {
instance;
public void test() {
}
}
- Effective Java 作者推荐使⽤枚举的⽅式解决单例模式。
3、总结
单例模式虽然是很常见的一种模式,但是具体实现方式有懒汉式、饿汉式、静态内部类、双重锁校验、CAS、枚举多种方法。