Java多线程 8种单例模式总结

文章目录

      • 不同写法对比
      • 为什么枚举是最好的单例模式写法
      • 使用的注意事项
      • 单例模式面试问题

不同写法对比

饿汉式: 写法简单, 但是没有lazy loading 懒加载
懒汉式: 如果写的不好, 会有线程安全问题. 尤其是在判断是否为空的地方
静态内部类: 可用 避免了线程安全问题和资源浪费的问题.

双重检查模式: 面试使用, 可以体现出很多的JMM知识 . 同时做到了线程安全和懒加载

枚举: 最好的写法. 生产中使用.

为什么枚举是最好的单例模式写法

  1. 《Effective Java》 这本书的作者提到, 枚举是单例模式的最佳写法
  2. 枚举的单例模式写法简单. 只需要创建一个枚举类, 一行代码创建实例就行了.
  3. 线程安全有保障: 由于枚举是特殊的类, 不需要程序员去保障线程安全, 枚举反编译后, 是成为了一个final修饰的类, 并且继承了枚举这个父类, 并且这个父类中的实例, 都是通过static定义的, 所以枚举的本质就是一个静态的对象, 那么第一次使用到枚举的时候, 才会被加载, 有懒加载的优点.
  4. 避免反序列化破坏单例: 其他单例模式的写法, 可能会被反射的写法所破坏. 比如通过反射会把私有的构造方法给绕过去, 或者反序列化也会反序列化出多个实例. 此时,如果使用枚举, 就避免了安全问题,防止反序列化创新创建新的对象.

使用的注意事项

  1. 枚举最好用
  2. 非线程同步的方法不能使用
  3. 如果程序一开始加载的资源多, 那么就应该使用懒加载
  4. 饿汉式的写法, 如果对象的创建需要配置文件或数据库中的数据就不适用. 因为一开始就实例好了一些对象, 但是还没加载好数据, 实际还是不可用的, 应该用懒汉式的懒加载
  5. 懒加载虽然好, 但是静态内部类这种方式会引入编程的复杂性.

单例模式面试问题

  1. 饿汉式的缺点
    类一加载的时候,就创建了实例, 如果不需要这个实例, 就造成了浪费,
  2. 懒汉式的缺点?
    虽然解决了前期加载资源浪费的问题, 只在需要的时候才加载 . 但是写法比较的复杂. 会有可能写成了线程不安全的情况.
  3. 为什么要用双重检查? 不用就不安全吗
    单个检查, 线程不安全, 两个线程可能同时进入单个检查的代码中, 造成创建了两个实例对象. 双重检查做到了懒加载和线程安全. 如果不用双重锁,把synchronized加在方法上,线程是安全的 , 那么造成性能的下降,
  4. 双重检查为什么要加volatile?
    因为构造单例模式, 创建实例对象的时候, 代表了三个步骤, 分别是创建一个空对象, 调用构造方法 , 最后是把实例的地址, 分配给引用. 但是这三个步骤顺序是不能保证的, 一旦调用构造方法这一步是最后一步了, 那么很有可能分配给引用的对象, 造成空指针的异常, 这样就造成了线程安全问题,加了volatile就避免了重排序, 并且加上了volatile, 第一个线程创建的单例的实例对象, 对于第二个线程也是可见的, 保证了可见性.
  5. 应该选择哪种单例模式的写法最好?
    用枚举的写法最好, 因为写法简单, 线程安全, 还能防止反序列化破坏单例.

你可能感兴趣的:(Java多线程基础与核心)