并发编程 - Condition
文章目录
前言
Condition实现对线程的阻塞、唤醒。
阻塞和唤醒方法的调用需要在lock.lock()与lock.unlock()之间,在阻塞的过程中会释放同步状态。
与wait方式不同的是,它额外支持响应中断、截止时间等待。与notify随机唤醒线程方式不同的是,Condition支持特定线程唤醒(等待队列中队首线程)。
Condition是通过AQS中的Node节点来创建一条单向链表作为等待队列(条件队列)。调用await()方法,则向这条链表的尾部中添加节点。调用signal()方法,则从链表的头部删除一个节点,并把这个节点添加到同步队列中(删除队列头部的一个节点),节点进入同步队列中之后,则有机会争夺CPU时间片。
在一条线程中是有多个condition的,而一个condition则有一个等待队列。多个condition则有多条等待队列。则一条线程有多个等待队列。而wait和notify在一个线程中只能有一个等待队列。
e.g.
public class ConditionDemo implements Runnable {
private static ReentrantLock lock = new ReentrantLock();
private static Condition condition = lock.newCondition();
@Override
public void run() {
try {
lock.lock();
condition.await();
System.out.println("Thread continued to do something.");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public static void main(String[] args) throws InterruptedException {
ConditionDemo demo = new ConditionDemo();
Thread thread = new Thread(demo);
thread.start();
Thread.sleep(5000);
lock.lock();
condition.signal();
lock.unlock();
}
}
await
使当前线程等待,自动释放关联的锁,响应中断。
有如下四种方式进行唤醒:
- 其他线程调用这个Condition关联的signal方法,当前线程恰好被选为被唤醒的线程。
- 其他线程调用这个Condition关联的signalAll方法。
- 其他线程中断了当前线程(支持线程中断)。
- 发生虚假的唤醒(spurious wakeup)。
该方法调用的时候需要获取Condition关联的锁。被唤醒之后,也需要重新获取Condition关联的锁。
AQS#await
接下来看下AQS里对于该方法的实现:
- 判断是否线程中断。
- 将当前线程封装成一个condition状态的节点。然后在条件队列队尾进行添加。
- 释放同步状态。
- 判断节点是否在条件队列中。如果在,则一直阻塞等待。
- 等待的过程中响应中断,尝试将节点转移到同步队列中。
- 线程被唤醒之后,尝试获取锁。
- 对线程中断进行处理。
addConditionWaiter
将当前线程封装成一个condition状态的节点。然后在条件队列队尾进行添加。
在条件队列中取消非condition状态的节点的链接。
firstWaiter、lastWaiter标记条件队列中的头节点、尾节点。
方法中使用的trail变量:用于暂存上一个condition状态的节点。
fullyRelease
释放同步状态。
isOnSyncQueue
判断节点是否处于同步队列中。
prev、next在同步队列中指代前驱节点、后继节点。
而条件队列中使用的是nextWaiter,指代后继节点。
前驱节点不为空,后继节点为空,则调用如下方法查找判断。
从尾节点开始,判断给定节点是否在同步队列中。
checkInterruptWhileWaiting
在等待的过程中,检查是否中断。
尝试将节点转移到同步队列中。
reportInterruptAfterWait
根据interruptMode采取抛出异常,执行线程中断或者什么都不做。
awaitUninterruptibly
与await不同的是:线程一开始调用该方法以及等待的过程中不响应中断。等待过程结束后再去对中断进行处理。
AQS#awaitUninterruptibly
awaitNanos
超时等待。
await(…)
超时等待。
awaitUntil
超时等待。
signal
唤醒一个条件等待的线程。
调用该方法时,需要先获取condition关联的锁。
AQS#signal
唤醒条件队列中的队首节点。
将条件队列中的节点转移到同步队列中。唤醒线程。
signalAll
唤醒所有条件等待的线程。
调用该方法时,需要先获取condition关联的锁。
AQS#signalAll
本文地址:https://blog.csdn.net/qq_34561892/article/details/109338290
下一篇: 记一次android面试