一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第5天,点击查看活动详情。
什么是线程通信
需要多个线程配合完成一件事情, 如何让多个线程能够合理的切换就是线程通信需要考虑的问题. 重点在于配合。
生产者消费者模式
生产者和消费者模式为最经典的线程通信案例
• 假设仓库中只能存放一件产品,生产者将生产出来的产品放入仓库,消费者将仓库中产品取走消费
• 如果仓库中没有产品,则生产者将产品放入仓库,否则停止生产并等待,直到仓库中的产品被消费者取走为止
• 如果仓库中放有产品,则消费者可以将产品取走消费,否则停止消费并等待,直到仓库中再次放入产品为止
生产商品实体类
/**
* @Classname Product
* @Description
* @Date 2022/4/5 11:50
* @Author Lee
*/
//生产商品的实体类
public class Product {
private String name; //馒头 玉米饼
private String color;//白色 黄色
private boolean flag;//库存的信号
public Product(){
}
public Product(String name, String color) {
this.name = name;
this.color = color;
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
@Override
public String toString() {
return "Product{" +
"name='" + name + ''' +
", color='" + color + ''' +
'}';
}
}
synchronized实现
/**
* @Classname TestA
* @Description
* @Date 2022/4/5 11:50
* @Author Lee
*/
public class TestA {
public static void main(String[] args) {
Product product = new Product();
new Thread(new ProduceRunnable(product)).start();
new Thread(new ConsumeRunnable(product)).start();
}
}
//生产者
class ProduceRunnable implements Runnable{
private static int num = 0;
private Product product;
public ProduceRunnable(Product product) {
this.product = product;
}
@Override
public void run() {
while (true) {
synchronized (product) {
//进行判断 如果信号是一个true代表库存中有内容 不需要在生产
if(product.isFlag()){
//当前线程处于等待状态
try {
product.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//程序如果可以运行到这个位置 代表没有库存 继续生产
if (num % 2 == 0) {
product.setColor("白色");
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
product.setName("馒头");
} else {
product.setColor("黄色");
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
product.setName("玉米饼");
}
System.out.println("生产者生产了:" + product.getColor() + "-" + product.getName());
product.setFlag(true);//代表已经生产了商品
product.notify();//通知消费者进行消费
num++;
}
}
}
}
//消费者
class ConsumeRunnable implements Runnable{
private Product product;
public ConsumeRunnable(Product product) {
this.product = product;
}
@Override
public void run() {
while (true){
synchronized (product) {
//如果进入if 代表当前没有库存的 消费者进行等待
if(!product.isFlag()){
try {
product.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("消费者消费了:" + product.getColor() + "-" + product.getName());
product.setFlag(false);//消费结束把flag变成false
product.notify();//通知生产者进行生产商品
}
}
}
}
=
这里的wait() 和 notify() 是Object总类中的方法 必须在有锁代码实现
wait()一直等待 wait(2000) 指定等待时间 wait(200,200)指定等待时间 毫秒+纳秒 将线程从运行 态变为阻塞态
notify() 随机唤醒一个等待的线程 如果在多个生产者和消费者的情况下 可能会出现唤醒线程错误
Lock实现
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @Classname TestB
* @Description
* @Date 2022/4/5 12:00
* @Author Lee
*/
public class TestB {
public static void main(String[] args) {
Product product = new Product();
Lock lock = new ReentrantLock();
//生产者等待队列
Condition Producecondition = lock.newCondition();
//消费者等待队列
Condition Consumecondition = lock.newCondition();
new Thread(new ProduceRunnable2(product,lock,Producecondition,Consumecondition)).start();
new Thread(new ConsumeRunnable2(product,lock,Producecondition,Consumecondition)).start();
}
}
//生产者
class ProduceRunnable2 implements Runnable{
private static int num = 0;
private Product product;
Lock lock;
Condition Producecondition;
Condition Consumecondition;
public ProduceRunnable2(Product product, Lock lock, Condition producecondition, Condition consumecondition) {
this.product = product;
this.lock = lock;
Producecondition = producecondition;
Consumecondition = consumecondition;
}
@Override
public void run() {
while (true) {
lock.lock();
//进行判断 如果信号是一个true代表库存中有内容 不需要在生产
if(product.isFlag()){
//当前线程处于等待状态
try {
Producecondition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//程序如果可以运行到这个位置 代表没有库存 继续生产
if (num % 2 == 0) {
product.setColor("白色");
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
product.setName("馒头");
} else {
product.setColor("黄色");
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
product.setName("玉米饼");
}
System.out.println("生产者生产了:" + product.getColor() + "-" + product.getName());
product.setFlag(true);//代表已经生产了商品
Consumecondition.signal();//通知消费者进行消费
num++;
lock.unlock();
}
}
}
//消费者
class ConsumeRunnable2 implements Runnable{
Lock lock;
private Product product;
Condition Producecondition;
Condition Consumecondition;
public ConsumeRunnable2(Product product,Lock lock, Condition producecondition, Condition consumecondition) {
this.lock = lock;
this.product = product;
Producecondition = producecondition;
Consumecondition = consumecondition;
}
@Override
public void run() {
while (true){
lock.lock();
//如果进入if 代表当前没有库存的 消费者进行等待
if(!product.isFlag()){
try {
Consumecondition.await(); //把线程加入消费者队列等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("消费者消费了:" + product.getColor() + "-" + product.getName());
product.setFlag(false);//消费结束把flag变成false
Producecondition.signal();//通知生产者进行生产商品
lock.unlock();
}
}
}
Condition用来替代传统的Object的wait()、notify()实现线程间的协作 它可以精确的唤醒等待的线程 与之相对应的方法是await(), signal()
一个Condition包含一个等待队列。一个Lock可以产生多个Condition,所以可以有多个等待队列