共计 2788 个字符,预计需要花费 7 分钟才能阅读完成。
AQS 中的 Condition 对象是用 于实现线程间通信和同步的对象,它能够和锁对象一起应用。Condition 对象的实现依赖于期待队列,它的次要作用是将期待某个条件的线程从期待队列中挪动到条件队列中,同时在条件满足时将它们从条件队列中移回到期待队列中。
1、办法介绍
1)Condition 对象的创立:Condition 对象是通过 Lock 接口中的 newCondition() 办法创立的。具体实现能够查看 ReentrantLock 和 ReentrantReadWriteLock 类中的 newCondition() 办法。
2)await() 办法的实现:await() 办法用于将以后线程退出到条件队列中,并且开释锁。具体实现中,它首先须要获取到以后线程对应的节点(Node 对象),而后将节点从期待队列中挪动到条件队列中,最初调用 release() 办法开释锁,并且挂起以后线程。
3)signal() 办法的实现:signal() 办法用于唤醒一个期待在条件队列中的线程,并且将它从条件队列中挪动到期待队列中。具体实现中,它首先须要获取到条件队列的头节点(firstWaiter),而后遍历条件队列,找到第一个不为 null 的节点,并且将它从条件队列中挪动到期待队列中,最初调用 unpark() 办法唤醒线程。
4)signalAll() 办法的实现:signalAll() 办法用于唤醒所有期待在条件队列中的线程,并且将它们从条件队列中挪动到期待队列中。具体实现中,它和 signal() 办法相似,只是在遍历条件队列时,将所有节点都挪动到期待队列中。
须要留神的是,Condition 对象的实现依赖于期待队列和 AQS 的实现,它的底层原理比较复杂。在应用 Condition 对象的时候,须要特地留神锁的开释和获取程序,以防止死锁等问题的呈现。
2、AQS 的哪些锁的实现用到了 condition 对象
AQS 中的 ReentrantLock 和 ReentrantReadWriteLock 都应用了 Condition 对象实现期待 / 告诉机制。
1)在 ReentrantLock 中,Condition 对象是通过 newCondition() 办法创立的,它是基于 AQS 的期待 / 告诉机制实现的。ReentrantLock 中的 Condition 对象和 ReentrantLock 对象是绑定的,即同一个 ReentrantLock 对象中能够创立多个 Condition 对象。线程在应用 Condition 对象期待某个条件时,须要先获取对应的锁,而后通过 Condition 对象的 await() 办法进入期待状态,并且开释锁。当条件满足时,线程能够通过 signal() 或 signalAll() 办法唤醒期待在条件队列中的线程,让它们从新进入到期待队列中期待获取锁。
2)在 ReentrantReadWriteLock 中,ReadLock 和 WriteLock 都实现了 Condition 接口。它们别离应用了两个 Condition 对象,别离用于实现读线程期待写线程开释锁的机制和写线程期待读线程开释锁的机制。
3、ReentrantLock 中 Condition 应用 demo
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ConditionDemo {private final Lock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
private boolean ready = false;
public void produce() {lock.lock();
try {
// 查看共享数据状态,如果共享数据曾经筹备好,就期待
while (ready) {condition.await();
}
// 生产共享数据
System.out.println("Producing data...");
// 标记共享数据状态
ready = true;
// 唤醒消费者线程
condition.signalAll();} catch (InterruptedException e) {e.printStackTrace();
} finally {lock.unlock();
}
}
public void consume() {lock.lock();
try {
// 查看共享数据状态,如果共享数据还没有筹备好,就期待
while (!ready) {condition.await();
}
// 生产共享数据
System.out.println("Consuming data...");
// 标记共享数据状态
ready = false;
// 唤醒生产者线程
condition.signalAll();} catch (InterruptedException e) {e.printStackTrace();
} finally {lock.unlock();
}
}
public static void main(String[] args) {final ConditionDemo demo = new ConditionDemo();
// 创立生产者线程
Thread producer = new Thread(() -> {while (true) {demo.produce();
}
});
// 创立消费者线程
Thread consumer = new Thread(() -> {while (true) {demo.consume();
}
});
// 启动生产者和消费者线程
producer.start();
consumer.start();}
}
在这个示例代码中,咱们创立了一个 ConditionDemo 类,其中蕴含了一个 ReentrantLock 和一个 Condition 对象。咱们通过 acquire() 和 release() 办法获取和开释锁,并且通过 await() 和 signalAll() 办法实现了线程间通信和同步。
具体实现中,咱们在 produce() 办法中获取锁并且查看共享数据状态,如果共享数据曾经筹备好,就期待,否则就生产共享数据,并且唤醒消费者线程。在 consume() 办法中,咱们也获取锁并且查看共享数据状态,如果共享数据还没有筹备好,就期待,否则就生产共享数据,并且唤醒生产者线程。
最初,咱们通过创立生产者和消费者线程,并且启动它们来模仿线程间通信和同步的过程。当运行这个示例代码时,咱们会看到生产者和消费者线程交替运行,并且输入相应的生产和生产信息。这个示例代码展现了如何应用 ReentrantLock 和 Condition 实现线程间通信和同步,它能够用作学习和参考多线程编程的例子。