还不知道ReentrantLock的实现流程,那你就out了

公平锁和非公平锁的区别锁的公平是相对于获取锁的顺序而言的 , 如果是一个公平锁 , 那么锁的获取顺序就应该符合请求的绝对时间顺序 , 也就是FIFO 。在上面分析的例子来说 , 只要CAS设置同步状态成功 , 则表示当前线程获取了锁 , 而公平锁则不一样 , 差异点有两个
FairSync.tryAcquire
final void lock() {acquire(1);}复制代码非公平锁在获取锁的时候 , 会先通过CAS进行抢占 , 则公平锁不会
FairSync.tryAcquire
protected final boolean tryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();if (c == 0) {if (!hasQueuedPredecessors() &&compareAndSetState(0, acquires)) {setExclusiveOwnerThread(current);return true;}}else if (current == getExclusiveOwnerThread()) {int nextc = c + acquires;if (nextc < 0)throw new Error("Maximum lock count exceeded");setState(nextc);return true;}return false;}}复制代码这个方法与 nonfairTryAcquire(int acquires)比较 , 不同的地方在于判断条件多了 hasQueuedPredecessors()方法 , 也就是加入了同步队列中当前节点是否有前驱节点的判断 , 如果该方法返回 true , 则表示有线程比当前线程更早地请求获取锁 ,  因此需要等待前驱线程获取并释放锁之后才能继续获取锁 。
Condition在synchronized中 , 有wait/notify可以实现线程的通信 。那么J.U.C里面提供了锁的实现机制 , 肯定也提供了线程通信的机制
Condition是一个多线程协调通信的工具类 , 可以让某些线程一起等待某个条件(condition) , 只有满足条件时 , 线程才会被唤醒
Condition基本使用public class ConditionDemoWait implements Runnable{private Lock lock;private Condition condition;public ConditionDemoWait(Lock lock , Condition condition){this.lock = lock;this.condition = condition;}public void run() {System.out.println("begin -ConditionDemoWait");try {lock.lock();condition.await();System.out.println("end - ConditionDemoWait");} catch (InterruptedException e) {e.printStackTrace();}finally {lock.unlock();}}}复制代码public class ConditionDemoSignal implements Runnable{private Lock lock;private Condition condition;public ConditionDemoSignal(Lock lock , Condition condition){this.lock = lock;this.condition = condition;}public void run() {System.out.println("begin -ConditionDemoSignal");try {lock.lock();condition.signal();System.out.println("end - ConditionDemoSignal");}finally {lock.unlock();}}public static void main(String[] args) {Lock lock = new ReentrantLock();Condition condition = lock.newCondition();new Thread(new ConditionDemoWait(lock , condition)).start();new Thread(new ConditionDemoSignal( lock , condition)).start();}}复制代码结果:
begin -ConditionDemoWaitbegin -ConditionDemoSignalend - ConditionDemoSignalend - ConditionDemoWait复制代码通过这个案例简单实现了wait和notify的功能 , 当调用await方法后 , 当前线程会释放锁并等待 , 而其他线程调用condition对象的signal或者signalall方法通知并被阻塞的线程 , 然后自己执行unlock释放锁 , 被唤醒的线程获得之前的锁继续执行 , 最后释放锁
所以 , condition中两个最重要的方法 , 一个是await , 一个是signal方法

  • await:把当前线程阻塞挂起
  • signal:唤醒阻塞的线程
Condition源码分析每一个Condition对象上面 , 都阻塞了多个线程 。因此 , 在ConditionObject内部也有一个双向链表 组成的队列 , 如下所示
public class ConditionObject implements Condition, JAVA.io.Serializable {private static final long serialVersionUID = 1173984872572414699L;/** First node of condition queue. */private transient Node firstWaiter;/** Last node of condition queue. */private transient Node lastWaiter;/*** Creates a new {@code ConditionObject} instance.*/public ConditionObject() { }}static final class Node {volatile Node prev;volatile Node next;volatile Thread thread;Node nextWaiter;}...复制代码调用Condition , 需要获取lock锁 , 所以意味着会存在一个AQS同步队列 , 先来看Condition.await方法
condition.await
调用Condition的await方法(或者以await开头的方法) , 会使当前线程进入等待队列并释放锁 , 同时线程状态变为等待状态 。当从await方法返回时 , 当前线程一定获取了Condition相关联的锁
public final void await() throws InterruptedException {if (Thread.interrupted())throw new InterruptedException();Node node = addConditionWaiter();//创建一个新的节点 , 节点状态为condition , 采用数据结构是链表int savedState = fullyRelease(node);//释放当前的锁 , 得到锁的状态 , 并唤醒AQS队列中的一个线程int interruptMode = 0;//如果当前节点没有在同步队列中 , 即还没有被signal , 则将当前线程阻塞while (!isOnSyncQueue(node)) {//判断这个节点是否在AQS队列上 , 第一次判断的是false , 因为前面已经释放锁了LockSupport.park(this);//第一次总是park自己 , 开始阻塞等待//线程判断自己在等待过程中是否被中断了 , 如果没有中断 , 则再次循环 , 会在isOnSyncQueue中判断自己是否在队列上//isOnSyncQueue判断当前node状态 , 如果是CONDITION状态 , 或者不在队列上了 , 就继续阻塞//isOnSyncQueue判断当前node还在队列上且不是CONDITION状态了 , 就结束循环和阻塞if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)break;}//当这个线程醒来 , 会尝试拿锁 , 当acquireQueued返回false就是拿到锁了//interruptMode != THROW_IE -> 表示这个线程没有成功将node入队 , 但signal执行了enq方法让其入队了//将这个变量设置成REINTERRUPTif (acquireQueued(node, savedState) && interruptMode != THROW_IE)interruptMode = REINTERRUPT;//如果node的下一个等待者不是null , 则进行清理 , 清理Condition队列上的节点//如果是null , 就没有什么好清理的了if (node.nextWaiter != null) // clean up if cancelledunlinkCancelledWaiters();//如果线程被中断了 , 需要抛出异常 , 或者什么都不做if (interruptMode != 0)reportInterruptAfterWait(interruptMode);}复制代码


推荐阅读