AQS——Condition使用
概述
1.Lock & Condtion & AQS关系
2.Lock & Condtion & AQS类图
3.Condtion实现生产者消费者模型
第1节 Lock & Condtion & AQS关系
等待通知机制,在Java中主要有两种方式:
一是基于wait/notify方法结合synchronized关键字来实现。
二是Condition结合Lock来实现。
前面我们学习了synchronized同步代码块,了解了java的内置锁,并学习了监视器锁的wait/notify机制。在大多数情况下,内置锁都能很好的工作,但它在功能上存在一些局限性,例如无法实现非阻塞结构的加锁规则等。为了拓展同步代码块中的监视器锁,java 1.5 开始,出现了lock接口,它实现了可定时、可轮询与可中断的锁获取操作,公平队列,以及非块结构的锁。
与内置锁不同,Lock是一种显式锁,它更加“危险”,因为在程序离开被锁保护的代码块时,不会像监视器锁那样自动释放,需要我们手动释放锁。所以,在我们使用Lock锁时,一定要记得:
在finally块中调用lock.unlock()手动释放锁!!!
在finally块中调用lock.unlock()手动释放锁!!!
在finally块中调用lock.unlock()手动释放锁!!!
监视器锁与Condition方法对比如下图所示。
第2节 Lock & Condtion & AQS类图
Lock与Condtion和AQS关系密切。Condition相关的类图如下。
第3节 Condtion实现生产者消费者模型
通过Condition可使线程按照不同的条件进行等待和唤醒。通过Condition提供的方法替代Object类的wait()和notify()方法,实现更加定制化的生产者-消费者模型。
通过Condition实现生产者-消费者模型,代码实现如下。
/**
* @Author: 【QQ:3190976240 email:zhouguanya20@163.com】
* @Date: 2019-09-02 23:05
* @Description: Condition实现生产者-消费者模型
*/
public class ProducerConsumer {
/**
* Lock
*/
private final Lock lock = new ReentrantLock();
/**
* 数组未满
*/
private final Condition notFull = lock.newCondition();
/**
* 数组非空
*/
private final Condition notEmpty = lock.newCondition();
/**
* 存储数据的底层数组
*/
private final Object[] items = new Object[100];
/**
* 输入数据的索引位置
*/
private int inputIndex;
/**
* 输出数据的索引位置
*/
private int outputIndex;
/**
* 计数器
*/
private int count;
/**
* 日期格式化
*/
private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:MM:ss SSS");
public static void main(String[] args) {
ExecutorService executorService = null;
try {
// Alibaba Java Coding Guidelines plugin 插件提示不要直接使用Executors
executorService = Executors.newCachedThreadPool();
ProducerConsumer producerConsumer = new ProducerConsumer();
// 10个生产者线程
for (int i = 0; i < 10; i++) {
executorService.submit(() -> {
for (int j = 0; j < 10; j++) {
try {
Thread.sleep(10);
producerConsumer.put(String.format("生产者%s于%s生产一条数据", Thread.currentThread().getName(), printDate()));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
// 1个消费者线程
executorService.submit(() -> {
try {
for (int i = 0; i < 100; i++) {
Object outPut = producerConsumer.take();
System.out.printf("消费者获取到数据%s%n", outPut);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
} finally {
assert executorService != null;
executorService.shutdown();
}
}
/**
* 生产者方法,往数组里面写数据
*
* @param input 输入数据
* @throws InterruptedException 中断异常
*/
public void put(Object input) throws InterruptedException {
lock.lock();
try {
while (count == items.length) {
//数组已满,没有空间时,挂起等待,直到数组“非满”(notFull)
notFull.await();
}
items[inputIndex] = input;
if (++inputIndex == items.length) {
inputIndex = 0;
}
++count;
// 因为放入了一个数据,数组肯定不是空的了
// 此时唤醒等待这notEmpty条件上的线程
notEmpty.signal();
} finally {
lock.unlock();
}
}
/**
* 消费者方法,从数组里面拿数据
*
* @return 数据
* @throws InterruptedException 中断异常
*/
public Object take() throws InterruptedException {
lock.lock();
try {
while (count == 0) {
// 数组是空的,没有数据可拿时,挂起等待,直到数组非空(notEmpty)
notEmpty.await();
}
Object x = items[outputIndex];
if (++outputIndex == items.length) {
outputIndex = 0;
}
--count;
// 因为拿出了一个数据,数组肯定不是满的了
// 此时唤醒等待这notFull条件上的线程
notFull.signal();
return x;
} finally {
lock.unlock();
}
}
/**
* 打印时间
*/
private static String printDate() {
return "【当前时间:" + simpleDateFormat.format(new Date()) + "】";
}
}
执行以上代码,执行结果如下。
消费者获取到数据生产者pool-1-thread-6于【当前时间:2019-09-29 11:09:12 521】生产一条数据
消费者获取到数据生产者pool-1-thread-5于【当前时间:2019-09-29 11:09:12 521】生产一条数据
消费者获取到数据生产者pool-1-thread-1于【当前时间:2019-09-29 11:09:12 519】生产一条数据
消费者获取到数据生产者pool-1-thread-10于【当前时间:2019-09-29 11:09:12 521】生产一条数据
消费者获取到数据生产者pool-1-thread-2于【当前时间:2019-09-29 11:09:12 521】生产一条数据
消费者获取到数据生产者pool-1-thread-7于【当前时间:2019-09-29 11:09:12 519】生产一条数据
消费者获取到数据生产者pool-1-thread-8于【当前时间:2019-09-29 11:09:12 521】生产一条数据
消费者获取到数据生产者pool-1-thread-9于【当前时间:2019-09-29 11:09:12 521】生产一条数据
消费者获取到数据生产者pool-1-thread-4于【当前时间:2019-09-29 11:09:12 521】生产一条数据
消费者获取到数据生产者pool-1-thread-3于【当前时间:2019-09-29 11:09:12 519】生产一条数据
消费者获取到数据生产者pool-1-thread-10于【当前时间:2019-09-29 11:09:12 536】生产一条数据
消费者获取到数据生产者pool-1-thread-6于【当前时间:2019-09-29 11:09:12 536】生产一条数据
消费者获取到数据生产者pool-1-thread-1于【当前时间:2019-09-29 11:09:12 536】生产一条数据
消费者获取到数据生产者pool-1-thread-3于【当前时间:2019-09-29 11:09:12 536】生产一条数据
消费者获取到数据生产者pool-1-thread-4于【当前时间:2019-09-29 11:09:12 536】生产一条数据
消费者获取到数据生产者pool-1-thread-9于【当前时间:2019-09-29 11:09:12 536】生产一条数据
消费者获取到数据生产者pool-1-thread-2于【当前时间:2019-09-29 11:09:12 536】生产一条数据
消费者获取到数据生产者pool-1-thread-8于【当前时间:2019-09-29 11:09:12 536】生产一条数据
消费者获取到数据生产者pool-1-thread-7于【当前时间:2019-09-29 11:09:12 536】生产一条数据
消费者获取到数据生产者pool-1-thread-5于【当前时间:2019-09-29 11:09:12 536】生产一条数据
消费者获取到数据生产者pool-1-thread-7于【当前时间:2019-09-29 11:09:12 546】生产一条数据
消费者获取到数据生产者pool-1-thread-4于【当前时间:2019-09-29 11:09:12 546】生产一条数据
消费者获取到数据生产者pool-1-thread-5于【当前时间:2019-09-29 11:09:12 546】生产一条数据
消费者获取到数据生产者pool-1-thread-6于【当前时间:2019-09-29 11:09:12 547】生产一条数据
消费者获取到数据生产者pool-1-thread-8于【当前时间:2019-09-29 11:09:12 547】生产一条数据
消费者获取到数据生产者pool-1-thread-3于【当前时间:2019-09-29 11:09:12 546】生产一条数据
消费者获取到数据生产者pool-1-thread-9于【当前时间:2019-09-29 11:09:12 546】生产一条数据
消费者获取到数据生产者pool-1-thread-10于【当前时间:2019-09-29 11:09:12 546】生产一条数据
消费者获取到数据生产者pool-1-thread-2于【当前时间:2019-09-29 11:09:12 546】生产一条数据
消费者获取到数据生产者pool-1-thread-1于【当前时间:2019-09-29 11:09:12 548】生产一条数据
消费者获取到数据生产者pool-1-thread-9于【当前时间:2019-09-29 11:09:12 557】生产一条数据
消费者获取到数据生产者pool-1-thread-7于【当前时间:2019-09-29 11:09:12 557】生产一条数据
消费者获取到数据生产者pool-1-thread-4于【当前时间:2019-09-29 11:09:12 557】生产一条数据
消费者获取到数据生产者pool-1-thread-10于【当前时间:2019-09-29 11:09:12 557】生产一条数据
消费者获取到数据生产者pool-1-thread-5于【当前时间:2019-09-29 11:09:12 557】生产一条数据
消费者获取到数据生产者pool-1-thread-8于【当前时间:2019-09-29 11:09:12 557】生产一条数据
消费者获取到数据生产者pool-1-thread-6于【当前时间:2019-09-29 11:09:12 557】生产一条数据
消费者获取到数据生产者pool-1-thread-3于【当前时间:2019-09-29 11:09:12 558】生产一条数据
消费者获取到数据生产者pool-1-thread-2于【当前时间:2019-09-29 11:09:12 558】生产一条数据
消费者获取到数据生产者pool-1-thread-1于【当前时间:2019-09-29 11:09:12 558】生产一条数据
消费者获取到数据生产者pool-1-thread-9于【当前时间:2019-09-29 11:09:12 568】生产一条数据
消费者获取到数据生产者pool-1-thread-10于【当前时间:2019-09-29 11:09:12 568】生产一条数据
消费者获取到数据生产者pool-1-thread-4于【当前时间:2019-09-29 11:09:12 568】生产一条数据
消费者获取到数据生产者pool-1-thread-6于【当前时间:2019-09-29 11:09:12 568】生产一条数据
消费者获取到数据生产者pool-1-thread-5于【当前时间:2019-09-29 11:09:12 568】生产一条数据
消费者获取到数据生产者pool-1-thread-7于【当前时间:2019-09-29 11:09:12 568】生产一条数据
消费者获取到数据生产者pool-1-thread-2于【当前时间:2019-09-29 11:09:12 568】生产一条数据
消费者获取到数据生产者pool-1-thread-8于【当前时间:2019-09-29 11:09:12 568】生产一条数据
消费者获取到数据生产者pool-1-thread-3于【当前时间:2019-09-29 11:09:12 568】生产一条数据
消费者获取到数据生产者pool-1-thread-1于【当前时间:2019-09-29 11:09:12 571】生产一条数据
消费者获取到数据生产者pool-1-thread-8于【当前时间:2019-09-29 11:09:12 580】生产一条数据
消费者获取到数据生产者pool-1-thread-2于【当前时间:2019-09-29 11:09:12 580】生产一条数据
消费者获取到数据生产者pool-1-thread-10于【当前时间:2019-09-29 11:09:12 580】生产一条数据
消费者获取到数据生产者pool-1-thread-3于【当前时间:2019-09-29 11:09:12 580】生产一条数据
消费者获取到数据生产者pool-1-thread-5于【当前时间:2019-09-29 11:09:12 580】生产一条数据
消费者获取到数据生产者pool-1-thread-4于【当前时间:2019-09-29 11:09:12 580】生产一条数据
消费者获取到数据生产者pool-1-thread-7于【当前时间:2019-09-29 11:09:12 580】生产一条数据
消费者获取到数据生产者pool-1-thread-9于【当前时间:2019-09-29 11:09:12 580】生产一条数据
消费者获取到数据生产者pool-1-thread-6于【当前时间:2019-09-29 11:09:12 580】生产一条数据
消费者获取到数据生产者pool-1-thread-1于【当前时间:2019-09-29 11:09:12 582】生产一条数据
消费者获取到数据生产者pool-1-thread-2于【当前时间:2019-09-29 11:09:12 591】生产一条数据
消费者获取到数据生产者pool-1-thread-8于【当前时间:2019-09-29 11:09:12 591】生产一条数据
消费者获取到数据生产者pool-1-thread-5于【当前时间:2019-09-29 11:09:12 591】生产一条数据
消费者获取到数据生产者pool-1-thread-7于【当前时间:2019-09-29 11:09:12 591】生产一条数据
消费者获取到数据生产者pool-1-thread-6于【当前时间:2019-09-29 11:09:12 591】生产一条数据
消费者获取到数据生产者pool-1-thread-9于【当前时间:2019-09-29 11:09:12 591】生产一条数据
消费者获取到数据生产者pool-1-thread-4于【当前时间:2019-09-29 11:09:12 591】生产一条数据
消费者获取到数据生产者pool-1-thread-3于【当前时间:2019-09-29 11:09:12 591】生产一条数据
消费者获取到数据生产者pool-1-thread-10于【当前时间:2019-09-29 11:09:12 591】生产一条数据
消费者获取到数据生产者pool-1-thread-1于【当前时间:2019-09-29 11:09:12 595】生产一条数据
消费者获取到数据生产者pool-1-thread-10于【当前时间:2019-09-29 11:09:12 602】生产一条数据
消费者获取到数据生产者pool-1-thread-4于【当前时间:2019-09-29 11:09:12 602】生产一条数据
消费者获取到数据生产者pool-1-thread-8于【当前时间:2019-09-29 11:09:12 602】生产一条数据
消费者获取到数据生产者pool-1-thread-7于【当前时间:2019-09-29 11:09:12 602】生产一条数据
消费者获取到数据生产者pool-1-thread-9于【当前时间:2019-09-29 11:09:12 602】生产一条数据
消费者获取到数据生产者pool-1-thread-2于【当前时间:2019-09-29 11:09:12 602】生产一条数据
消费者获取到数据生产者pool-1-thread-3于【当前时间:2019-09-29 11:09:12 602】生产一条数据
消费者获取到数据生产者pool-1-thread-5于【当前时间:2019-09-29 11:09:12 602】生产一条数据
消费者获取到数据生产者pool-1-thread-6于【当前时间:2019-09-29 11:09:12 603】生产一条数据
消费者获取到数据生产者pool-1-thread-1于【当前时间:2019-09-29 11:09:12 606】生产一条数据
消费者获取到数据生产者pool-1-thread-10于【当前时间:2019-09-29 11:09:12 613】生产一条数据
消费者获取到数据生产者pool-1-thread-2于【当前时间:2019-09-29 11:09:12 612】生产一条数据
消费者获取到数据生产者pool-1-thread-9于【当前时间:2019-09-29 11:09:12 613】生产一条数据
消费者获取到数据生产者pool-1-thread-5于【当前时间:2019-09-29 11:09:12 613】生产一条数据
消费者获取到数据生产者pool-1-thread-7于【当前时间:2019-09-29 11:09:12 613】生产一条数据
消费者获取到数据生产者pool-1-thread-4于【当前时间:2019-09-29 11:09:12 612】生产一条数据
消费者获取到数据生产者pool-1-thread-8于【当前时间:2019-09-29 11:09:12 612】生产一条数据
消费者获取到数据生产者pool-1-thread-3于【当前时间:2019-09-29 11:09:12 613】生产一条数据
消费者获取到数据生产者pool-1-thread-6于【当前时间:2019-09-29 11:09:12 613】生产一条数据
消费者获取到数据生产者pool-1-thread-1于【当前时间:2019-09-29 11:09:12 617】生产一条数据
消费者获取到数据生产者pool-1-thread-5于【当前时间:2019-09-29 11:09:12 624】生产一条数据
消费者获取到数据生产者pool-1-thread-3于【当前时间:2019-09-29 11:09:12 624】生产一条数据
消费者获取到数据生产者pool-1-thread-6于【当前时间:2019-09-29 11:09:12 624】生产一条数据
消费者获取到数据生产者pool-1-thread-4于【当前时间:2019-09-29 11:09:12 624】生产一条数据
消费者获取到数据生产者pool-1-thread-9于【当前时间:2019-09-29 11:09:12 624】生产一条数据
消费者获取到数据生产者pool-1-thread-7于【当前时间:2019-09-29 11:09:12 624】生产一条数据
消费者获取到数据生产者pool-1-thread-8于【当前时间:2019-09-29 11:09:12 624】生产一条数据
消费者获取到数据生产者pool-1-thread-10于【当前时间:2019-09-29 11:09:12 625】生产一条数据
消费者获取到数据生产者pool-1-thread-2于【当前时间:2019-09-29 11:09:12 625】生产一条数据
消费者获取到数据生产者pool-1-thread-1于【当前时间:2019-09-29 11:09:12 630】生产一条数据