目录
Condition
接口简介
任意一个 Java
对象都拥有一组监视器方法(定义在 java.lang.Object
上),主要包括 wait()、wait(long timeout)、notify()
以及 notifyAll()
方法,这些方法与 synchronized
同步关键字配合,可以实现线程之间的等待,唤醒
在 jdk 1.5
之后提供了 Lock
接口,Lock
又提供了条件 Condition
接口,使得对线程的等待、唤醒操作更加详细和灵活。Condition
接口与 Lock
配合也可以实现线程之间的等待,唤醒;但是这两者在使用方式以及功能特性上还是有差别的
对比项 | Object 监视器方法 | Condition |
---|---|---|
前置条件 | 获取对象的锁 | 1.调用Lock.lock()获取 2.调用Lock.newCondition()获取Condition对象 |
调用方式 | 直接调用,如object.wait() |
直接调用,如condition.await() |
等待队列个数 | 一个 | 多个 |
当前线程释放锁并进入等待状态 | 支持 | 支持 |
当前线程释放锁并进入等待状态,在等待状态中不响应终端 | 不支持 | 支持 |
当前线程释放锁并进入超时等待状态 | 支持 | 支持 |
当前线程释放锁并进入等待状态到将来的某个时间 | 不支持 | 支持 |
唤醒等待队列中的一个线程 | 支持 | 支持 |
唤醒等待队列中的全部线程 | 支持 | 支持 |
- 一个
Lock
对象里可以创建多个condition
实例,线程可以注册在指定的condition
中从而选择性的进行线程通知,在调度线程上更加灵活 - 在使用
notify(),notifuAll()
方法进行唤醒时,被调度的线程是由cpu
随机选择的。但使用ReentrantLock
结合condition
是可以实现选择性通知
,这个功能是非常重要的,而且在condition
类中默认提供的 - 而
synchronized
就相当于整个Lock
对象中只有一个单一的condition
对象,所有的线程都注册在它一个对象上。线程开始notifyAll()
时,需要通知所有的WAITING
线程,没有选择权 Conditon
中的await()
对应Object
的wait()
Condition
中的signal()
对应Object
的notify()
Condition
中的signalAll()
对应Object
的notifyAll()
Condition
的应用
@Slf4j
public class ProducerConsumerTest {
private final Lock lock = new ReentrantLock();
// 通过Lock获取两个Condition实例
private final Condition addCondition = lock.newCondition();
private final Condition removeCondition = lock.newCondition();
private final LinkedList<Integer> resources = new LinkedList<>();
private final int maxSize;
public ProducerConsumerTest(int maxSize) {
this.maxSize = maxSize;
}
public class Producer implements Runnable {
private final int proSize;
private Producer(int proSize) {
this.proSize = proSize;
}
@Override
public void run() {
lock.lock();
try {
for (int i = 1; i < proSize; i++) {
log.info("已经生产产品数: " + i + "\t现仓储量总量:" + resources.size());
resources.add(i);
while (resources.size() >= maxSize) {
log.info("当前仓库已满,等待消费...");
try {
// 进入阻塞状态
addCondition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 唤醒消费者
removeCondition.signal();
}
} finally {
lock.unlock();
}
}
}
public class Consumer implements Runnable {
@Override
public void run() {
String threadName = Thread.currentThread().getName();
while (true) {
lock.lock();
try {
while (resources.size() <= 0) {
log.info(threadName + " 当前仓库没有产品,请稍等...");
try {
// 进入阻塞状态
removeCondition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}