Java中单例模式定义:“一个类有且仅有一个实例,并且自行实例化向整个系统提供。”
单例模式应用的场景一般发现在以下条件下:
(1)资源共享的情况下,避免由于资源操作时导致的性能或损耗等。如上述中的日志文件,应用配置。
(2)控制资源的情况下,方便资源之间的互相通信。如线程池等。
第一种 饿汉模式
定义:在类加载的时候就立即初始化,并且创建单例对象。绝对线程安全,在线程还没出现以前就是实例化了,不可能存在访问安全问题。
优点:没有加任何的锁、执行效率比较高,在用户体验上来说,比懒汉式更好。
缺点:类加载的时候就初始化,不管用与不用都占着空间,浪费了内存。
Spring 中 IOC 容器 ApplicationContext 本身就是典型的饿汉式单例。
public class HungrySingleton { public static HungrySingleton hungrySingleton = null; static { hungrySingleton = new HungrySingleton(); } private HungrySingleton() { } public HungrySingleton getInstance() { return hungrySingleton; } }
第二种 懒汉式单例
懒汉式单例的特点是:被外部类调用的时候内部类才会加载。
扫描二维码关注公众号,回复:
11255210 查看本文章
public class LazySingleton { public static LazySingleton lazySingleton = null; private LazySingleton() { } //synchronized 解决多线程并发安全问题 public synchronized static LazySingleton getInstance() { if (lazySingleton == null) { lazySingleton = new LazySingleton(); } return lazySingleton; } }
第三种 双重检查锁单例
线程安全的问题虽然解决了。但是,用synchronized 加锁,在线程数量比较多情况下,如果 CPU 分配压力上升,会导致大批量线程出现阻塞,从而导致程序运行性能大幅下降。
那么,有没有一种更好的方式,既兼顾线程安全又提升程序性能呢?答案是肯定的。我们来看双重检查锁的单例模式:
public class DoubleLockCheckSingleton { // volatile可以实现多线程的可见性 有序性 但是不保证一致性 public volatile static DoubleLockCheckSingleton doubleLockCheckSingleton = null; private DoubleLockCheckSingleton() {} public static DoubleLockCheckSingleton getInstance() { // 最外成if 过滤掉不为null 的线程 提高效率 if (doubleLockCheckSingleton == null) { synchronized (DoubleLockCheckSingleton.class) { if (doubleLockCheckSingleton == null) { doubleLockCheckSingleton = new DoubleLockCheckSingleton(); } } } return doubleLockCheckSingleton; } }
第四种 内部类单例
虽然双重检查锁确实优化了很多,但是,用到 synchronized 关键字,总归是要上锁,对程序性能还是存在一定影响的。难道就真的没有更好的方案吗?
当然是有的。我们可以从类初始化角度来考虑,
内部类一定是要在方法调用之前初始化,巧妙地避免了线程安全问题。
/** * 内部类 线程安全 懒汉式 * 完美的解决类懒汉时的内存浪费和synchronized的性能问题 */ public class InnerClassSingleton { private InnerClassSingleton () { // 防止被反射破坏 if (InnerClassHolder.innerClassSingleton == null) { throw new RuntimeException("不允许创建多实例"); } } // static为了使用单利内存共性 final为了让方法不被重写 重载 public static final InnerClassSingleton getInstance() { return InnerClassHolder.innerClassSingleton; } // 默认不加载 使用的时候才会加载 private static class InnerClassHolder { private static final InnerClassSingleton innerClassSingleton = new InnerClassSingleton(); } }