生产者和消费者(等待唤醒机制)
- 等待唤醒机制
- 常见方法
- 代码演示
- 等待唤醒机制(阻塞队列方式实现)
- 额外扩展
等待唤醒机制
生产者和消费者是一个十分经典的多线程协作模式
举个小栗子来说明一下消费者和生产者的等待唤醒过程:
常见方法
- void wait() 当前线程等待,直到被其他线程唤醒
- void notify() 随机唤醒单个线程
- void notifyAll() 唤醒所有线程
代码演示
接下来,使用代码来演示生产者和消费者的等待唤醒过程
1、消费者代码:
package com.heima.thread001;
public class FoodThread extends Thread {
@Override
public void run() {
while (true){
synchronized (Desk.lock){
if (Desk.count == 0){
break;
}else {
//判断桌子上有没有面条
if (Desk.foodFlag == 0){
//如果没有,就等待
try {
Desk.lock.wait();//让当前线程跟锁进行绑定
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
//把吃的总数-1
Desk.count--;
//如果有,就开吃
System.out.println("吃货在吃面条,还能再吃" + Desk.count + "碗");
//吃完之后,唤醒厨师继续做
Desk.lock.notifyAll();
//修改桌子的状态
Desk.foodFlag = 0;
}
}
}
}
}
}
2、生产者代码
package com.heima.thread001;
public class CookThread extends Thread {
@Override
public void run() {
while (true){
synchronized (Desk.lock){
//判断桌子上有没有面条
if (Desk.count == 0){
break;
}else {
//判断桌子上是否有实物
if(Desk.foodFlag == 1){
//如果有,就等待
try {
Desk.lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}else {
//如果没有,就制作面条
System.out.println("厨师做了一碗面条");
//修改桌子上的食物状态
Desk.foodFlag = 1;
//叫醒等待的消费者开吃
Desk.lock.notifyAll();
}
}
}
}
}
}
3、控制生产者和消费者的执行类
package com.heima.thread001;
public class Desk {
/**
* 作用:控制生产者和消费者的执行
*/
//是否有面条 0:没有面条 1:有面条
public static int foodFlag = 0;
//总个数
public static int count = 10;
//锁对象
public static Object lock = new Object();
}
4、测试类
package com.heima.thread001;
public class TestDemo {
public static void main(String[] args){
CookThread cookThread = new CookThread();
FoodThread foodThread = new FoodThread();
cookThread.setName("厨师");
foodThread.setName("吃货");
cookThread.start();
foodThread.start();
}
}
5、运行结果
Connected to the target VM, address: '127.0.0.1:52025', transport: 'socket'
Disconnected from the target VM, address: '127.0.0.1:52025', transport: 'socket'
厨师做了一碗面条
吃货在吃面条,还能再吃9碗
厨师做了一碗面条
吃货在吃面条,还能再吃8碗
厨师做了一碗面条
吃货在吃面条,还能再吃7碗
厨师做了一碗面条
吃货在吃面条,还能再吃6碗
厨师做了一碗面条
吃货在吃面条,还能再吃5碗
厨师做了一碗面条
吃货在吃面条,还能再吃4碗
厨师做了一碗面条
吃货在吃面条,还能再吃3碗
厨师做了一碗面条
吃货在吃面条,还能再吃2碗
厨师做了一碗面条
吃货在吃面条,还能再吃1碗
厨师做了一碗面条
吃货在吃面条,还能再吃0碗
Process finished with exit code 0
等待唤醒机制(阻塞队列方式实现)
阻塞队列的继承结构
代码演示:
生产者代码
package com.heima.thread001;
import java.util.concurrent.ArrayBlockingQueue;
public class CookThread extends Thread {
ArrayBlockingQueue<String> queue;
public CookThread(ArrayBlockingQueue<String> queue){
this.queue = queue;
}
@Override
public void run() {
while (true){
//不断把面条放到阻塞队列中
try {
queue.put("面条");
System.out.println("厨师放了一碗面条");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
消费者
package com.heima.thread001;
import java.util.concurrent.ArrayBlockingQueue;
public class FoodThread extends Thread {
ArrayBlockingQueue<String> queue;
public FoodThread(ArrayBlockingQueue<String> queue){
this.queue = queue;
}
@Override
public void run() {
while (true){
//不断的从阻塞队列中获取面条
try {
String food = queue.take();
System.out.println(food);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
测试类
package com.heima.thread001;
import java.util.concurrent.ArrayBlockingQueue;
public class TestDemo {
public static void main(String[] args){
ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(1);
CookThread c = new CookThread(queue);
FoodThread f = new FoodThread(queue);
c.start();
f.start();
}
}
额外扩展
wait()、notify()、notifyAll()方法
Object类里面提供了这几个方法:
wait():让当前线程处于等待(阻塞状态),直到其他线程调用此对象的notify()或notifyAll()方法(进入就绪状态)。
notify():唤醒在此对象监视器上等待的单个线程。
notifyAll():唤醒在此对象监视器上等待的所有线程。
每个方法都有finnal关键字修饰。
为什么这些方法要定义在Object类里,而不定义在Thread类里呢?
因为这些方法的调用必须通过锁对象调用,而锁对象可以是任意对象。所以定义在Object类里。