面试官问我AQS中的PROPAGATE有什么用?

本文通过分析Semaphore的实现,探讨了AQS中的PROPAGATE状态的重要性。Semaphore利用AQS实现共享资源的管理,PROPAGATE状态用于避免线程无法被正确唤醒的问题,确保并发场景下的锁释放与获取能够正确协调。文章详细解释了一个可能导致线程无法唤醒的Bug,并通过引入PROPAGATE状态来解决这个问题。同时,文中还提及doReleaseShared方法在并发控制中的关键作用。
摘要由CSDN通过智能技术生成

之前分析过AQS的源码,但只分析了独占锁的原理。

而刚好我们可以借助Semaphore来分析共享锁。

如何使用Semaphore

public class SemaphoreDemo {
   

  public static void main(String[] args) {
   

    // 申请共享锁数量
    Semaphore sp = new Semaphore(3);

    for(int i = 0; i < 5; i++) {
   
      new Thread(() -> {
   
        try {
   

          // 获取共享锁
          sp.acquire();

          String threadName = Thread.currentThread().getName();

          // 访问API
          System.out.println(threadName + " 获取许可,访问API。剩余许可数 " + sp.availablePermits());

          TimeUnit.SECONDS.sleep(1);
          
          // 释放共享锁
          sp.release();

          System.out.println(threadName + " 释放许可,当前可用许可数为 " + sp.availablePermits());

        } catch (InterruptedException e) {
   
            e.printStackTrace();
        }

      }, "thread-" + (i+1)).start();
    }
  }
}

Java SDK 里面提供了 Lock,为啥还要提供一个 Semaphore ?其实实现一个互斥锁,仅仅是 Semaphore 的部分功能,Semaphore 还有一个功能是 Lock 不容易实现的,那就是:Semaphore 可以允许多个线程访问一个临界区。

比较常见的需求就是我们工作中遇到的连接池、对象池、线程池等等池化资源。其中,你可能最熟悉数据库连接池,在同一时刻,一定是允许多个线程同时使用连接池的,当然,每个连接在被释放前,是不允许其他线程使用的。

比如上面的代码就演示了同时最多只允许3个线程访问API。

如何依托AQS实现Semaphore

abstract static class Sync extends AbstractQueuedSynchronizer {
   
  Sync(int permits) {
   
    setState(permits);
  }

  // 获取锁
  final int nonfairTryAcquireShared(int acquires) {
   
    for (;;) {
   
      int available = getState();
      int remaining = available - acquires;
      if (remaining < 0 ||
          compareAndSetState(available, remaining
AQS(AbstractQueuedSynchronizer)和ReentrantLock是Java并发包中两种不同的同步机制。 1. **工作原理不同**: - AQS是一种底层的、无锁的同步结构,依赖于一系列的状态标志来控制同步流程。它主要用于构建更复杂的同步工具,如Semaphore、CountDownLatch等。 - ReentrantLock则是一个内置锁机制,拥有显式的锁和unlock操作,允许线程多次获取锁(reentrant,即自含回路),并且有公平和不公平两种获取策略。 2. **并发性能**: - AQS由于其内部设计,通常适用于轻量级的同步场景,避免了锁争抢导致的频繁上下文切换。但在竞争激烈的环境中,AQS可能会造成线程堆积。 - ReentrantLock提供了可中断和定时锁等功能,适合需要更多定制化同步需求的应用。 3. **使用体验**: - AQS的API相对简单,通常通过回调函数的方式来处理同步事件,开发者需要自己编写同步代码。 - ReentrantLock则提供了更为直观和易于理解的API,支持更多的同步操作,如检查是否已获取锁、超时获取锁等。 4. **公平性**: - AQS默认是非公平的,最近的请求优先被服务;而ReentrantLock可以设置为公平模式,保证所有线程按顺序获取锁。 5. **中断与响应**: - ReentrantLock支持中断线程,AQS则没有这种特性。 总的来说,AQS更适合追求高性能、灵活性和自定义的场合,而ReentrantLock则是为了提供更丰富的功能和易用性。选择哪一个取决于具体的项目需求。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值