本节内容主要是对 Java 锁机制之 Condition 接口进行讲解,Condition 接口是配合 Lock 接口使用的,我们已经学习过 Lock 接口的相关知识,那么接下来对 Condition 接口进行讲解。本节内容的知识点如下:
任意一个 Java 对象,都拥有一组监视器方法(定义在 java.lang.Object 上),主要包括 wait ()、wait (long timeout)、notify () 以及 notifyAll () 方法。这些方法与 synchronized 同步关键字配合,可以实现等待 / 通知模式。
定义:Condition 接口也提供了类似 Object 的监视器方法,与 Lock 配合可以实现等待 / 通知模式。Condition 可以看做是 Obejct 类的 wait ()、notify ()、notifyAll () 方法的替代品,与 Lock 配合使用。
我们看到,从 JDK 的源码中可以获悉,Condition 接口包含了如下的方法,对于其中常用的方法,我们在后续的内容中会有比较详细的讲解。
public interface Condition {
void await() throws InterruptedException;
long awaitNanos(long nanosTimeout) throws InterruptedException;
boolean await(long time, TimeUnit unit) throws InterruptedException;
boolean awaitUntil(Date deadline) throws InterruptedException;
void signal();
void signalAll();
}
联系 1:都有一组类似的方法.
联系 2:都需要和锁进行关联。
区别:
Condition 对象是由 Lock 对象创建出来的 (Lock.newCondition),换句话说,Condition 是依赖 Lock 对象的。那么我们来看看如果创建 Condition 对象。
此处仅提供示例代码,后续我们在进行方法讲解时,会有全部的代码示例,但在学习使用方法之前,我们必须先学会如何创建。
Lock lock = new ReentrantLock();
Condition condition1 = lock.newCondition();
Condition condition2 = lock.newCondition();
等待机制方法简介:
通知机制方法简介:
非常熟悉的场景设计,这是我们在讲解生产者与消费者模型时使用的案例设计,那么此处有细微的修改如下,请学习者进行比照学习,印象更加深刻。
场景修改:
实例:
public class DemoTest {
public static void main(String[] args) {
ProductFactory productFactory = new ProductFactory();
new Thread(new Producer(productFactory),"1号生产者"). start();
new Thread(new Producer(productFactory),"2号生产者"). start();
new Thread(new Consumer(productFactory),"1号消费者"). start();
new Thread(new Consumer(productFactory),"2号消费者"). start();
new Thread(new Consumer(productFactory),"3号消费者"). start();
}
}
class ProductFactory {
private LinkedList<String> products; //根据需求定义库存,用 LinkedList 实现
private int capacity = 10; // 根据需求:定义最大库存 10
private Lock lock = new ReentrantLock(false);
private Condition p = lock.newCondition();
private Condition c = lock.newCondition();
public ProductFactory() {
products = new LinkedList<String>();
}
// 根据需求:produce 方法创建
public void produce(String product) {
try {
lock.lock();
while (capacity == products.size()) { //根据需求:如果达到 10 库存,停止生产
try {
System.out.println("警告:线程("+Thread.currentThread().getName() + ")准备生产产品,但产品池已满");
p.await(); // 库存达到 10 ,生产线程进入 wait 状态
} catch (InterruptedException e) {
e.printStackTrace();
}
}
products.add(product); //如果没有到 10 库存,进行产品添加
System.out.println("线程("+Thread.currentThread().getName() + ")生产了一件产品:" + product+";当前剩余商品"+products.size()+"个");
c.signalAll(); //生产了产品,通知消费者线程从 wait 状态唤醒,进行消费
} finally {
lock.unlock();
}
}
// 根据需求:consume 方法创建
public String consume() {
try {
lock.lock();
while (products.size()==0) { //根据需求:没有库存消费者进入wait状态
try {
System.out.println("警告:线程("+Thread.currentThread().getName() + ")准备消费产品,但当前没有产品");
c.await(); //库存为 0 ,无法消费,进入 wait ,等待生产者线程唤醒
} catch (InterruptedException e) {
e.printStackTrace();
}
}
String product = products.remove(0) ; //如果有库存则消费,并移除消费掉的产品
System.out.println("线程("+Thread.currentThread().getName() + ")消费了一件产品:" + product+";当前剩余商品"+products.size()+"个");
p.signalAll();// 通知生产者继续生产
return product;
} finally {
lock.unlock();
}
}
}
class Producer implements Runnable {
private ProductFactory productFactory; //关联工厂类,调用 produce 方法
public Producer(ProductFactory productFactory) {
this.productFactory = productFactory;
}
public void run() {
int i = 0 ; // 根据需求,对产品进行编号
while (true) {
productFactory.produce(String.valueOf(i)); //根据需求 ,调用 productFactory 的 produce 方法
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
i++;
}
}
}
class Consumer implements Runnable {
private ProductFactory productFactory;
public Consumer(ProductFactory productFactory) {
this.productFactory = productFactory;
}
public void run() {
while (true) {
productFactory.consume();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
结果验证:
线程(1号生产者)生产了一件产品:0;当前剩余商品1个
线程(2号生产者)生产了一件产品:0;当前剩余商品2个
线程(1号消费者)消费了一件产品:0;当前剩余商品1个
线程(2号消费者)消费了一件产品:0;当前剩余商品0个
警告:线程(3号消费者)准备消费产品,但当前没有产品
线程(2号生产者)生产了一件产品:1;当前剩余商品1个
线程(1号生产者)生产了一件产品:1;当前剩余商品2个
线程(3号消费者)消费了一件产品:1;当前剩余商品1个
线程(2号消费者)消费了一件产品:1;当前剩余商品0个
警告:线程(1号消费者)准备消费产品,但当前没有产品
本节内容为主要对 Condition 接口进行了讲解,Condition 接口作为 Lock 接口的监视器,是非常重要的接口,我们需要非常重视 Condition 接口的学习。
本节内容最终的目的是使用 Condition 接口和 Lock 配合实现案例,核心内容即为 Condition 接口的使用,请翻看生产者与消费者一节,对比进行学习。
0/1000