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

总结:

  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. 关键代码如下:
                  
  private static AtomicBoolean shouldEnter = new AtomicBoolean(false);
  private static AtomicBoolean shouldLeave = new AtomicBoolean(false);
  private static volatile ThreadSafeSingleton instance;

  private ThreadSafeSingleton() {
  }

  public static ThreadSafeSingleton getInstance() {
    if (instance == null) {
      if (shouldEnter.compareAndSet(false, true)) {
        instance = new ThreadSafeSingleton();
        shouldLeave.set(true);
      }

      while (!shouldLeave.get()) {
      }
    }
    return instance;
  }

<think>好的,我现在需要回答用户关于Java中synchronizedReentrantLock的区别,以及如何实现线程安全单例模式的问题。首先,我得回忆一下两者的基本概念区别。 synchronized是Java的关键字,属于内置的锁机制,而ReentrantLock是java.util.concurrent包下的一个类,需要显式地加锁解锁。记得ReentrantLock提供了更多的灵活性,比如可中断的锁获取、定时锁等待、公平性选择等,而synchronized则相对简单,但可能在性能上不如ReentrantLock优化后的版本。 接下来是单例模式线程安全实现。常见的可能有饿汉式、懒汉式加锁、双重检查锁定等。需要确保在多线程环境下只生成一个实例。其中,双重检查锁定需要注意volatile关键字的使用,防止指令重排序导致的问题。另外,使用静态内部类或者枚举类的方式也是线程安全的,可能更简洁。 需要检查是否有遗漏的要点,比如锁的释放、异常处理、性能比较等。在单例模式部分,可能需要详细说明各种实现方式的优缺点,以及为什么某些方法更推荐。同时,要确保代码示例正确,比如在双重检查锁中使用volatile,否则可能导致问题。另外,ReentrantLock在单例中的应用可能不太常见,但也可以作为一种方法,不过可能不如其他方式简洁。 还要注意引用用户提供的参考中的LockReentrantLock的导入语句,但用户的问题是关于synchronizedReentrantLock的区别,所以可能需要关联到这些引用,但原引用内容似乎只是一个代码片段,可能没有直接相关的信息,所以可能不需要特别引用,除非在回答中提到ReentrantLock的具体用法时需要。不过用户提供的引用可能不太相关,所以可能不引用或者仅作为锁实现的示例。 最后,生成相关问题需要考虑用户可能的后续疑问,比如性能对比、适用场景、其他设计模式等。需要确保问题相关且有引导性。</think>### Java中synchronized与ReentrantLock的区别 #### 1. **实现机制** - **synchronized** 是Java语言内置的关键字,基于JVM底层实现,通过`monitorenter``monitorexit`指令实现锁的获取与释放。锁的获取释放由JVM自动管理,无需手动控制。 - **ReentrantLock** 是`java.util.concurrent.locks`包下的类,基于API实现,需显式调用`lock()``unlock()`方法,且必须通过`try-finally`块确保锁的释放[^1]。 #### 2. **功能特性** - **灵活性**: ReentrantLock支持以下特性,而synchronized不支持: - **可中断锁**:通过`lockInterruptibly()`允许线程在等待锁时响应中断。 - **公平锁**:可指定锁的公平性(默认非公平),减少线程饥饿问题。 - **超时机制**:通过`tryLock(long timeout, TimeUnit unit)`设置锁等待超时。 - **条件变量**: ReentrantLock可通过`newCondition()`创建多个条件队列,精准控制线程的等待与唤醒;synchronized仅支持单一条件队列。 #### 3. **性能差异** - 在低竞争场景下,synchronized因JVM优化(如偏向锁、轻量级锁)性能与ReentrantLock接近。 - 高竞争场景下,ReentrantLock通过减少上下文切换更细粒度的控制,性能更优。 #### 4. **代码示例对比** ```java // synchronized实现线程安全 public synchronized void syncMethod() { // 临界区代码 } // ReentrantLock实现线程安全 private final ReentrantLock lock = new ReentrantLock(); public void lockMethod() { lock.lock(); try { // 临界区代码 } finally { lock.unlock(); } } ``` --- ### 线程安全单例模式实现 #### 1. **饿汉式(线程安全)** ```java public class Singleton { private static final Singleton INSTANCE = new Singleton(); private Singleton() {} public static Singleton getInstance() { return INSTANCE; } } ``` - **优点**:实现简单,无锁性能高。 - **缺点**:类加载时即初始化实例,可能浪费资源。 #### 2. **双重检查锁定(Double-Checked Locking)** ```java public class Singleton { private static volatile Singleton INSTANCE; private Singleton() {} public static Singleton getInstance() { if (INSTANCE == null) { synchronized (Singleton.class) { if (INSTANCE == null) { INSTANCE = new Singleton(); } } } return INSTANCE; } } ``` - **关键点**:`volatile`修饰符禁止指令重排序,避免返回未完全初始化的实例。 #### 3. **静态内部类(推荐)** ```java public class Singleton { private static class Holder { static final Singleton INSTANCE = new Singleton(); } private Singleton() {} public static Singleton getInstance() { return Holder.INSTANCE; } } ``` - **原理**:利用类加载机制保证线程安全,延迟初始化且无需同步。 #### 4. **枚举类(最佳实践)** ```java public enum Singleton { INSTANCE; // 其他方法 } ``` - **优点**:简洁、线程安全、自动防反射攻击,推荐作为单例的标准实现。 --- ### 对比总结 | 特性 | synchronized | ReentrantLock | |---------------------|----------------------------------|-----------------------------| | **锁释放** | 自动释放(代码块/方法结束) | 手动调用`unlock()` | | **公平性** | 仅支持非公平锁 | 支持公平与非公平锁 | | **锁中断** | 不支持 | 支持可中断锁 | | **条件变量** | 单一条件队列 | 多条件队列 | | **适用场景** | 简单同步需求 | 复杂并发控制 | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值