概要
什么是线程通信呢?
当多个线程共同操作共享资源时,线程间通过某种方式互相告知自己的状态,以相互协调,避免无效的资源挣抢。
下面用一个线程通线的常见模式:生产者与消费者模型来展示何为线程通信,以及线程通信的一个应用场景
案例内容
- 生产者线程负责生成数据
- 消费者线程负责消费生产者生成的数据
- 注意:生产者生产完数据后应该让自己等待,通知其他消费者消费;消费者消费完数据之后应该让自己等待,同时通知生产者生成
案例思路
1.先确定在这个案例中,什么是共享数据?
答:这里案例中桌子是共享数据,因为厨师和顾客都需要对桌子上的包子进行操作。
2.再确定有那几条线程?哪个是生产者,哪个是消费者?
答:厨师是生产者线程,3条生产者线程;
顾客是消费者线程,2条消费者线程
3.什么时候将哪一个线程设置为什么状态
生产者线程(厨师)放包子:
1)先判断是否有包子
2)没有包子时,厨师开始做包子, 做完之后把别人唤醒,然后让自己等待
3)有包子时,不做包子了,直接唤醒别人、然后让自己等待
消费者线程(顾客)吃包子:
1)先判断是否有包子
2)有包子时,顾客开始吃包子, 吃完之后把别人唤醒,然后让自己等待
3)没有包子时,不吃包子了,直接唤醒别人、然后让自己等待
代码实现
桌子类
public class Desk {
private List<String> list = new ArrayList<>();
// 放1个包子的方法
// 厨师1 厨师2 厨师3
public synchronized void put() {
try {
String name = Thread.currentThread().getName();
// 判断是否有包子。
if(list.size() == 0){
list.add(name + "做的肉包子");
System.out.println(name + "做了一个肉包子~~");
Thread.sleep(2000);
// 唤醒别人, 等待自己
this.notifyAll();
this.wait();
}else {
// 有包子了,不做了。
// 唤醒别人, 等待自己
this.notifyAll();
this.wait();
}
} catch (Exception e) {
e.printStackTrace();
}
}
// 吃货1 吃货2
public synchronized void get() {
try {
String name = Thread.currentThread().getName();
if(list.size() == 1){
// 有包子,吃了
System.out.println(name + "吃了:" + list.get(0));
list.clear();
Thread.sleep(1000);
this.notifyAll();
this.wait();
}else {
// 没有包子
this.notifyAll();
this.wait();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
测试类
public class ThreadTest {
public static void main(String[] args) {
// 需求:3个生产者线程,负责生产包子,每个线程每次只能生产1个包子放在桌子上
// 2个消费者线程负责吃包子,每人每次只能从桌子上拿1个包子吃。
Desk desk = new Desk();
// 创建3个生产者线程(3个厨师)
new Thread(() -> {
while (true) {
desk.put();
}
}, "厨师1").start();
new Thread(() -> {
while (true) {
desk.put();
}
}, "厨师2").start();
new Thread(() -> {
while (true) {
desk.put();
}
}, "厨师3").start();
// 创建2个消费者线程(2个吃货)
new Thread(() -> {
while (true) {
desk.get();
}
}, "吃货1").start();
new Thread(() -> {
while (true) {
desk.get();
}
}, "吃货2").start();
}
}
小结
通过线程通信可以使多个线程相互协调执行,避免无效的资源挣抢,极大提高开发效率