「这是我参与11月更文挑战的第9天,活动详情查看:2021最后一次更文挑战」
生产者消费者模式概述
生产者消费者模式是一个十分经典的多线程协作的模式,弄懂生产者消费者问题能够让我们对多线程编程的理解更加深刻。
等待和唤醒的方法:
为了体现生产和消费过程中的等待和唤醒,java就提供了几个方法供我们使用,这几个方法在Object类中 Object类的等待和唤醒方法:
public class Desk {
// 定义一个标记
// true 就表示桌子上有汉堡包的,此时运行吃货执行。
// false 就表示 桌子上没有汉堡包的,此时允许厨师执行
public static boolean flag = false;
// 汉堡包的总数量
public static int count = 10;
// 锁对象
public static final Object lock = new Object();
}
public class Foodie extends Thread{
@Override
public void run() {
// 1. 判断桌子上是否有汉堡包。
// 2. 如果没有就等待。
// 3. 如果有就开吃。
// 4. 吃完之后,桌子上的汉堡包就没有了。叫醒等待的生产者继续生产,汉堡包的总数量减一。
while (true){
synchronized (Desk.lock){
if (Desk.count == 0){
break;
}else {
if (Desk.flag){
// 有
System.out.println("吃货在吃汉堡包");
Desk.flag = false;
Desk.lock.notifyAll();
Desk.count--;
}else {
// 没有就等待
// 使用什么对象当做锁,那么就必须用这个对象去调用等待和唤醒的方法。
try {
Desk.lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
}
public class Cooker extends Thread{
@Override
public void run() {
while (true){
synchronized (Desk.lock){
if (Desk.count == 0){
break;
}else {
if (!Desk.flag){
// 没有
System.out.println("厨师正在生产汉堡包");
Desk.flag = true;
Desk.lock.notifyAll();
}else {
try {
Desk.lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
}
public class Demo {
public static void main(String[] args) {
// 消费者步骤:
// 1. 判断桌子上是否有汉堡包。
// 2. 如果没有就等待。
// 3. 如果有就开吃。
// 4. 吃完之后,桌子上的汉堡包就没有了。叫醒等待的生产者继续生产,汉堡包的总数量减一。
// 生产者步骤:
// 1. 判断桌子上是否有汉堡包。
// 如果有就等待,如果没有才生产。
// 2. 把汉堡包放在桌子上。
// 3. 叫醒等待的消费者开吃。
Foodie f = new Foodie();
Cooker c = new Cooker();
f.start();
c.start();
}
}
改造一下:
public class Desk {
// 定义一个标记
// true 就表示桌子上有汉堡包的,此时运行吃货执行。
// false 就表示 桌子上没有汉堡包的,此时允许厨师执行
// public static boolean flag = false;
private boolean flag;
// 汉堡包的总数量
// public static int count = 10;
// 以后我们在使用这种必须有默认值的变量
private int count;
// 锁对象
// public static final Object lock = new Object();
private final Object lock = new Object();
public Desk() {
this(false,10);
}
public Desk(boolean flag, int count) {
this.flag = flag;
this.count = count;
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
public Object getLock() {
return lock;
}
@Override
public String toString() {
return "Desk{" +
"flag=" + flag +
", count=" + count +
", lock=" + lock +
'}';
}
}
public class Foodie extends Thread{
private Desk desk;
public Foodie(Desk desk) {
this.desk = desk;
}
@Override
public void run() {
// 1. 判断桌子上是否有汉堡包。
// 2. 如果没有就等待。
// 3. 如果有就开吃。
// 4. 吃完之后,桌子上的汉堡包就没有了。叫醒等待的生产者继续生产,汉堡包的总数量减一。
while (true){
synchronized (desk.getLock()){
if (desk.getCount() == 0){
break;
}else {
if (desk.isFlag()){
// 有
System.out.println("吃货在吃汉堡包");
desk.setFlag(false);
desk.getLock().notifyAll();
desk.setCount(desk.getCount() - 1);
}else {
// 没有就等待
// 使用什么对象当做锁,那么就必须用这个对象去调用等待和唤醒的方法。
try {
desk.getLock().wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
}
public class Cooker extends Thread{
private Desk desk;
public Cooker(Desk desk) {
this.desk = desk;
}
@Override
public void run() {
while (true){
synchronized (desk.getLock()){
if (desk.getCount() == 0){
break;
}else {
if (!desk.isFlag()){
// 没有
System.out.println("厨师正在生产汉堡包");
desk.setFlag(true);
desk.getLock().notifyAll();
}else {
try {
desk.getLock().wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
}
public class Demo {
public static void main(String[] args) {
// 消费者步骤:
// 1. 判断桌子上是否有汉堡包。
// 2. 如果没有就等待。
// 3. 如果有就开吃。
// 4. 吃完之后,桌子上的汉堡包就没有了。叫醒等待的生产者继续生产,汉堡包的总数量减一。
// 生产者步骤:
// 1. 判断桌子上是否有汉堡包。
// 如果有就等待,如果没有才生产。
// 2. 把汉堡包放在桌子上。
// 3. 叫醒等待的消费者开吃。
Desk desk = new Desk();
Foodie f = new Foodie(desk);
Cooker c = new Cooker(desk);
f.start();
c.start();
}
}
阻塞队列实现等待唤醒机制
阻塞队列基本用法:
public class Demo {
public static void main(String[] args) throws InterruptedException {
// 阻塞队列的基本用法:
// 创建阻塞队列的对象,容量为1
ArrayBlockingQueue<String> arrayBlockingQueue = new ArrayBlockingQueue<>(1);
// 存储元素
arrayBlockingQueue.put("汉堡包");
// 取元素
System.out.println(arrayBlockingQueue.take());
System.out.println(arrayBlockingQueue.take());
System.out.println("程序结束了");
}
}
public class Cooker extends Thread{
private ArrayBlockingQueue<String> list;
public Cooker(ArrayBlockingQueue<String> list) {
this.list = list;
}
@Override
public void run() {
while (true){
try {
list.put("汉堡包");
System.out.println("厨师放了一个汉堡包");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Foodie extends Thread{
private ArrayBlockingQueue<String> list;
public Foodie(ArrayBlockingQueue<String> list) {
this.list = list;
}
@Override
public void run() {
while (true){
try {
String take = list.take();
System.out.println("吃货从队列中获取了" + take);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class Demo {
public static void main(String[] args) {
// 创建一个阻塞队列,容量为1
ArrayBlockingQueue<String> list = new ArrayBlockingQueue<>(1);
// 创建线程并开启
Cooker c = new Cooker(list);
Foodie f = new Foodie(list);
c.start();
f.start();
}
}