天天看点

不用synchronized和lock,实现线程安全的单例模式

转自(https://blog.csdn.net/vincentff7zg/article/details/58057668)

总结:

  1. 单例模式必然会被多个线程访问。多线程访问一定要注意锁的问题。
  2. 参考博主之前分享的转载文章《java中的锁》,有几种方式如下:
    1. 自旋锁
    2. 类锁和对象锁
    3. 共享锁和排它锁
    4. 偏向锁
    5. 互斥锁
    6. 闭锁
    7. 活锁
    8. 分段锁
    9. 无锁
      1. 无状态编程
      2. 线程本地存储
      3. volatile
      4. CAS
      5. 协程
  3. 不使用synchronized和lock这两种工具,但仍可以参考其他方案:
    1. 无状态编程:不适用
    2. 线程本地存储:例如lock加速性能用。不适用
    3. volatile:必须使用,构造wall
    4. CAS:可以使用,代替lock或者synchronized
    5. 协程:不适用
  4. 考虑使用volatile+CAS,例如volatile+atomicboolean
  5. 具体来说,需要实现类似synchronized和lock的关键区域的入口和出口的功能,入口通过BtomicBoolean shouldEnter.compareAndSet(false,true)实现,并在其中new实例,然后标记可以进入出口了即AtomicBoolean shouldLeave.set()。随后,在外层用shouldLeave.isset()判定。
  6. 注意,由于有入口出口以及new对象,同样有new时创建了实例退出关键区域但还没有来得及初始化的问题,volatile可以解决。
  7. 关键代码如下:
  1. private static AtomicBoolean shouldEnter = new AtomicBoolean( false);
  2. private static AtomicBoolean shouldLeave = new AtomicBoolean( false);
  3. private static volatile ThreadSafeSingleton instance;
  4. private ThreadSafeSingleton() {
  5. }
  6. public static ThreadSafeSingleton getInstance() {
  7. if (instance == null) {
  8. if (shouldEnter.compareAndSet( false, true)) {
  9. instance = new ThreadSafeSingleton();
  10. shouldLeave.set( true);
  11. }
  12. while (!shouldLeave.get()) {
  13. }
  14. }
  15. return instance;
  16. }

转自(https://blog.csdn.net/vincentff7zg/article/details/58057668)

总结:

  1. 单例模式必然会被多个线程访问。多线程访问一定要注意锁的问题。
  2. 参考博主之前分享的转载文章《java中的锁》,有几种方式如下:
    1. 自旋锁
    2. 类锁和对象锁
    3. 共享锁和排它锁
    4. 偏向锁
    5. 互斥锁
    6. 闭锁
    7. 活锁
    8. 分段锁
    9. 无锁
      1. 无状态编程
      2. 线程本地存储
      3. volatile
      4. CAS
      5. 协程
  3. 不使用synchronized和lock这两种工具,但仍可以参考其他方案:
    1. 无状态编程:不适用
    2. 线程本地存储:例如lock加速性能用。不适用
    3. volatile:必须使用,构造wall
    4. CAS:可以使用,代替lock或者synchronized
    5. 协程:不适用
  4. 考虑使用volatile+CAS,例如volatile+atomicboolean
  5. 具体来说,需要实现类似synchronized和lock的关键区域的入口和出口的功能,入口通过BtomicBoolean shouldEnter.compareAndSet(false,true)实现,并在其中new实例,然后标记可以进入出口了即AtomicBoolean shouldLeave.set()。随后,在外层用shouldLeave.isset()判定。
  6. 注意,由于有入口出口以及new对象,同样有new时创建了实例退出关键区域但还没有来得及初始化的问题,volatile可以解决。
  7. 关键代码如下:
  1. private static AtomicBoolean shouldEnter = new AtomicBoolean( false);
  2. private static AtomicBoolean shouldLeave = new AtomicBoolean( false);
  3. private static volatile ThreadSafeSingleton instance;
  4. private ThreadSafeSingleton() {
  5. }
  6. public static ThreadSafeSingleton getInstance() {
  7. if (instance == null) {
  8. if (shouldEnter.compareAndSet( false, true)) {
  9. instance = new ThreadSafeSingleton();
  10. shouldLeave.set( true);
  11. }
  12. while (!shouldLeave.get()) {
  13. }
  14. }
  15. return instance;
  16. }