admin管理员组

文章数量:1599543

这里不讲代码,只是用图大概描述Condition在ReentrantLock中做了一件怎么样的事情。

流程描述

Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();

当多个线程开始抢占ReentrantLock的锁时

lock.lock();


ReentrantLock锁时互斥的,同一时刻只可能有一个线程获取到使用权,其他没有抢到的则乖乖进入等待队列,等待被唤醒。

当抢到独占锁的线程调用Condition的await方法时,线程开始阻塞

condition.await();

这里为了condition队列好理解,就假设T1、T2先后调用了await方法,释放了独占锁。


此时T1、T2先后调用了await·的方法的线程会被加入到ConditionObject对象的双向队列中分别对应firstWaiterlastWaiter,加入完成之后,释放独占锁,并阻塞自身等待其他持独占锁的线程调用signal释放

T3成了锁的持有者,上面俩哥都等着斥锁人来通知他们。

当持锁的线程调用signal方法时,队列会发生变化

condition.signal(); 


这里要注意的是:调用signal方法并不会唤醒condition中的线程
比如这里的场景:

  1. T3 调用了signal方法,会先从condition队列中找到等待时间最长的,【先进先出嘛,第一个进去的肯定是排队最长的。】
  2. 拿到T1线程之后,将T1线程加入到AQS队列中排着。

其实这里就是做了线程从队列中的迁移,不会被立即唤醒,毕竟T3还没释放呢!T1从一开始持有锁的时候,也是自己先释放才能唤醒下一个线程。

这时候持R锁的T3释放锁了

当T3释放锁的时候,按照之前流程串起来。
排在等待队列的T1被唤醒,成为持锁人。

当然会存在一些竞争情况,比如这时候排队的可能不是T1,又或者T3释放锁的一瞬间,T456又来竞争锁。
如果T1没有抢到,则乖乖在等待队里里面待着。

不会影响流程。

总结

  1. 同一时刻只有一个对象获取独占锁,持有了这个锁的人才能调用await和sign方法。
  2. await方法会释放独占锁,并且将自身加入到condition队列中。
  3. signal方法不会立即唤醒await中的线程,而是将Condition队列中的线程转移到AQS队列中。
  4. 当持锁线程释放锁时,AQS队列的线程再抢到则会被唤醒。

以上言论仅个人理解,欢迎交流,共同探讨!

本文标签: 方法场景简单conditionReentrantLock