背景
解决多线程环境下,各个线程间的通信问题
应用场景
生产者和消费者问题
核心实现方式
方法 | 说明 |
---|---|
wait() | 线程会一直等待,直到其他线程通知,与sleep不同,wait()会释放锁 |
wait(long timeout) | 指定等待的毫秒数 |
notify() | 唤醒一个处于等待状态的线程 |
notifyAll() | 唤醒同一个对象上所有调用wait()方法的线程,优先级高的线程,优先调度 |
注意:上述方法均是Object类的方法,只能在 同步方法 或者 同步代码块 中使用,否则会抛出 IIIegalMonitorStateException
实现方式
- 管程法
- 信号灯法
举例说明
1、管程法实现
场景:商家生产蛋糕,将蛋糕放到柜子里,消费者购买蛋糕,从柜子里取出蛋糕
涉及通信问题:商家生产了蛋糕,就可以通知消费者过来购买蛋糕;消费者买空了柜子里的蛋糕,就应该通知商家生产
代码实现
package com.wei.thread.commute;
/**
* @author: wei
* @date 2022/5/4 21:57
* 说明:生产者与消费者通信问题测试
**/
public class TestProducerConsumer {
public static void main(String[] args) {
IceBox iceBox = new IceBox();
Shop shop = new Shop(iceBox);
Consumer consumer = new Consumer(iceBox);
shop.start();
consumer.start();
}
}
// 商家
class Shop extends Thread {
IceBox iceBox;
public Shop(IceBox iceBox) {
this.iceBox = iceBox;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("商家生产蛋糕,编号:" + i);
iceBox.push(new Cake(i));
}
}
}
// 消费者
class Consumer extends Thread {
IceBox iceBox;
public Consumer(IceBox iceBox) {
this.iceBox = iceBox;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
Cake cake = iceBox.pop();
System.out.println("取到蛋糕,编号为:" + cake.id);
}
}
}
// 蛋糕
class Cake {
int id;
public Cake(int id) {
this.id = id;
}
}
// 冷藏柜
class IceBox {
// 冰柜大小, 可以放10个蛋糕
Cake[] cakes = new Cake[10];
int count = 0;
public synchronized void push(Cake cake) {
if (count == cakes.length) {
// 停止生产,等待
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 将蛋糕放入冰柜,并通知消费者过来购买
cakes[count] = cake;
count++;
this.notifyAll();
}
public synchronized Cake pop() {
Cake cake = null;
if (count <= 0) {
// 没有蛋糕了,通知商家生产,并在此等待
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
cake = cakes[--count];
this.notifyAll();
return cake;
}
}
2、信号灯法实现
场景:
涉及通信问题:
代码实现