Java并发编程系列-AbstractQueuedSynchronizer (2)

Condition是一个接口,旨在定义一系列针对获取锁的线程的操作,实现类似于Object类中wait/notify的功能。我们通过其方法定义可以明显感觉到这一点。

public interface Condition { // 使当前线程等待,知道被唤醒或者中断,注意需要在临界区使用,执行该方法之后该线程持有的锁将被释放,线程处于等待状态 // 四种情况下会退出等待状态:被signal唤醒,被signalAll唤醒,被interrupt唤醒(需要当前线程可以响应中断),发生伪唤醒 void await() throws InterruptedException; // 使当前线程等待,直到被唤醒(不响应中断),注意要在临界区使用,执行该方法之后该线程持有的锁将被释放,线程处于等待状态 // 三种情况下会退出等待状态:被signal唤醒,被signalAll唤醒,发生伪唤醒 void awaitUninterruptibly(); // 使当前线程等待,知道被唤醒或者中断或者超时,注意需要在临界区使用,执行该方法之后该线程持有的锁将被释放,线程处于等待状态 // 五种情况下会退出等待状态:被signal唤醒,被signalAll唤醒,被interrupt唤醒(需要当前线程可以响应中断),超时,发生伪唤醒 // nanosTimeout表示当前线程要等待的时间长度 // 该方法返回一个正数表示线程被提前唤醒,返回一个负数或0表示等待超时 long awaitNanos(long nanosTimeout) throws InterruptedException; // 同上,不同在于上面的只能传参为纳秒值,该方法可以通过单位随便传值 boolean await(long time, TimeUnit unit) throws InterruptedException; // 使当前线程等待,知道被唤醒或者中断或者过了截止日期,注意需要在临界区使用,执行该方法之后该线程持有的锁将被释放,线程处于等待状态 // 退出等待状态的情况同上,只是这里传参为一个固定的时间点,线程等待到这个时间点将自动苏醒 boolean awaitUntil(Date deadline) throws InterruptedException; // 唤醒等待队列中的一个线程,该线程从await返回时必须获取到锁 void signal(); // 唤醒等待队列中的所有线程,每个线程从await返回时必须获取到锁 void signalAll(); } 2.2.3 ConditionObject

ConditionObject是Condition的实现类,在AQS中以普通内部类的方式存在。

ConditionObject内部维护了一个单向链表实现的等待队列,队列的节点与AQS中同步队列的节点类型一致,均为上面的内部类Node类型。

下面我们来仔细看看这个类:

(1)体系结构 public class ConditionObject implements Condition, java.io.Serializable {}

该类实现了Condition接口和Serializable接口,拥有序列化功能

(2)字段 public class ConditionObject implements Condition, java.io.Serializable { // 序列化ID private static final long serialVersionUID = 1173984872572414699L; // 等待队列头结点指针 private transient Node firstWaiter; // 等待队列尾节点指针 private transient Node lastWaiter; // 中断模式 private static final int REINTERRUPT = 1;// 退出等待队列时重新中断 private static final int THROW_IE = -1;// 退出等待队列时抛出InterruptedException异常 }

我们可以看到类的五个字段中除了三个静态字段之外,剩下的两个被transient修饰,也就是说虽然该类支持序列化,但是序列化无值。

(3)方法

ConditionObject中的公共方法其实就是对Condition接口中定义方法的实现,下面我们逐个分析:

await()

public class ConditionObject implements Condition, java.io.Serializable { public final void await() throws InterruptedException { // 1-响应中断,同时会清除中断标记 if (Thread.interrupted()) throw new InterruptedException(); // 2-将当前线程封装成Node节点并添加到等待队列尾部 Node node = addConditionWaiter(); // 3-释放当前线程所占用的lock,在释放的过程中会唤醒同步队列中的下一个节点 int savedState = fullyRelease(node); int interruptMode = 0; // 4-阻塞当前线程,直到被中断或者被唤醒 while (!isOnSyncQueue(node)) {// 校验当前线程是否被唤醒(是否被转移到同步队列),如果已唤醒则退出循环 LockSupport.park(this);// 阻塞当前线程 if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)// 校验当前线程是否被中断 break;// 如果被中断则退出循环 } // 5-自旋等待获取到同步状态(即获取到lock) if (acquireQueued(node, savedState) && interruptMode != THROW_IE) interruptMode = REINTERRUPT; if (node.nextWaiter != null) // clean up if cancelled unlinkCancelledWaiters(); // 6-处理被中断的情况 if (interruptMode != 0) reportInterruptAfterWait(interruptMode); } }

方法解析:

第一步:优先响应中断,首先校验当前线程是否被中断,如果被中断则抛出InterruptedException异常,否则下一步;

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwwysj.html