消费者/生产者(条件变量)
在这里我以画图的形式来说明它的设计思路
代码如下(代码中的注释很全,方便理解):
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import com.alibaba.fastjson.JSON;
/**
* 条件变量Condition锁
*
* @author onlyone
*/
public class ConditionDemo {
//可重入锁 也叫做递归锁 指的是同一线程 外层函数获得锁之后 (可重入锁最大的作用是避免死锁)
//内层递归函数仍然有获取该锁的代码,但不受影响
//在JAVA环境下 ReentrantLock和 synchronized 都是 可重入锁
private ReentrantLock lock = new ReentrantLock();
//并且创建两个condition,相当于两个阻塞
//条件变量1
private Condition take = lock.newCondition();
//条件变量2
private Condition put = lock.newCondition();
//阻塞队列(先进先出)
private BlockingQueue queue = new ArrayBlockingQueue<>(10000);
// 队列的最大容量
private int capacity = 5;
// 初始值
private int i = 1;
//往队列里面插入数据
public void put() {
lock.lock(); //获得锁
System.out.println(String.format("【put】i=%d 获取锁!!!", i));
try {
//使用while的目的:它醒了之后你得用while循环让它再去判断一次条件
while (queue.size() == capacity) {
System.out.println(String.format("【put】插入 %d 时队列满,执行put.await!队列值:【%s】", i,
JSON.toJSONString(queue.toArray())));
put.await();//条件阻塞
}
queue.put(i);
System.out.println(String.format("【put】插入 %d 到队列", i));
i++;
// 读操作唤醒
take.signal(); //条件唤醒
} catch (Exception e) {
} finally {
System.out.println(String.format("【put】i=%d 释放锁!!!", i - 1));
lock.unlock(); //释放锁 一般放在finally里
}
}
/**
* 从队列读数据
*/
public void take() {
lock.lock(); //获取锁
System.out.println("【take】获取锁!");
int data = 0;
try {
//使用while的目的:它醒了之后你得用while循环让它再去判断一次条件
while (queue.size() == 0) {
System.out.println("【take】执行take.await!");
take.await();//条件阻塞
}
data = (int) queue.take();
System.out.println(String.format("【take】从队列读取值 %d ,队列值:【%s】", data, JSON.toJSONString(queue.toArray())));
// 写操作唤醒
put.signal();//条件唤醒
} catch (Exception e) {
} finally {
System.out.println(String.format("【take】i=%d 释放锁!!!", data));
lock.unlock(); //释放锁 一般放在finally
}
}
}
测试代码:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TestClass {
// 写任务
static class WriteTask implements Runnable {
private ConditionDemo condition;
public WriteTask(ConditionDemo condition){
this.condition = condition;
}
@Override
public void run() {
condition.put();
}
}
// 读任务
static class ReadTask implements Runnable {
private ConditionDemo condition;
public ReadTask(ConditionDemo condition){
this.condition = condition;
}
public void run() {
condition.take();
}
}
public static void main(String[] args) throws InterruptedException {
ConditionDemo condition = new ConditionDemo();
//类似于一个线程池的功能
for (int i = 0; i < 20; i++) {
new Thread(new WriteTask(condition)).start();;
}
for (int i = 0; i < 20; i++) {
new Thread(new ReadTask(condition)).start();;
}
}
}
效果: