6.2 线程协作
6.2.1 生产者消费模式
- 应用场景:生产者和消费者 问题
假设仓库中只能存放一件产品,生产者将生产出来的产品放入仓库,消费者将仓库中的产品取走消费。
如果仓库中没有产品,则生产者将 产品放入仓库,否则停止生产并等待,直到仓库中的产品被消费者取走为止。
如果仓库中放有产品,则消费者可以将产品取走消费,否则停止消费并等待,直到仓库中再次放入产品位置。
6.2.2 线程通讯-分析
这是一个线程同步问题,生产者和消费者 共享一个资源,并且生产者和消费者 之间相互依赖,互为条件。
- 对于生产者而言,没有生产产品之前,要通知消费者进行等待。而生产了产品之后,又必须马上通知消费者让它进行消费。
- 对于消费者而言,在消费之后,要通知生产者,消费已结束。需要再次生产新的产品 供给自己消费。
- 在生产者消费者问题中,仅仅 用 synchronized 是完全不够的!
synchronized 只能阻止 并发更新同一个共享资源的问题,实现了 线程同步。
synchronized 不能用来实现不同线程之间的消息传递(通信)<因为 其它线程 直接 处于阻塞状态,还 通讯 个 屁了 ~ ~ 所以才需要 wait() 方法 和 notifyAll() 方法>
方法名 | 作用 |
---|---|
wait() | 表示线程一直等待,直到其它线程通知你,才会解除等待状态,与 sleep 不同的是,它会释放锁!也就是可以实现 线程间的通讯。 |
wait(long timeout) | 指定等待的毫秒数 |
notify() | 唤醒一个处于等待状态的线程 |
notifyAll() | 唤醒同一个对象上所有调用过 wait()方法的线程,优先级别高的线程优先调度 |
6.2.3 管程法
代码设计流程:
-
创建两个 事务,一个生产者事务,一个消费者事务
-
创建一个 数据缓冲区,用于 操作 数据
-
数据缓冲区里面,写两个 synchronized 方法 一个是生产者 处理数据的方法,一个是 消费者处理数据的方法。
-
创建 一个数据结构体,用来 说明我们要 处理的数据。
-
生产者事务里 会新建 很多的 该数据对象
-
消费者事务里 会释放 很多的 该数据对象
-
创建 一个 数据缓冲区的 数据存储器
-
生产者处理数据的方法 是接收 生产者事务 传递过来的 数据。并 判断 是否 继续接收。
-
消费者处理数据的方法 是接收的 数据 返回给 消费者事务,让消费者事务 进行 实质性的 消费!
package www.muquanyu.Seniorpart;public class 管程法 {
public static void main(String[] args) throws InterruptedException {
DataBuffer dataBuffer = new DataBuffer();Producer producer = new Producer(dataBuffer);Consumer consumer= new Consumer(dataBuffer);producer.start();Thread.sleep(1);consumer.start();}}class Producer extends Thread {
DataBuffer dataBuffer;public Producer(DataBuffer dataBuffer){
this.dataBuffer = dataBuffer;}@Overridepublic void run(){
for(int i = 0;i<100;++i){
chick chick = new chick(i);System.out.println("生产出第:"+ (i+1) +"只鸡!");try {
dataBuffer.producermethod(chick);} catch (InterruptedException e) {
e.printStackTrace();}}System.out.println("所有鸡生产完毕!");}}class Consumer extends Thread{
DataBuffer dataBuffer;public Consumer(DataBuffer dataBuffer){
this.dataBuffer = dataBuffer;}@Overridepublic void run(){
for(int i = 0;i<100;++i){
chick consumermethod = null;try {
consumermethod = dataBuffer.consumermethod();} catch (InterruptedException e) {
e.printStackTrace();}System.out.println("消费掉第:"+ consumermethod.id +"只鸡!");}System.out.println("所有鸡消费完毕!");}
}//小鸡的结构体
class chick{
int id;chick(int id){
this.id = id;}
}//数据缓冲区(是专门存储数据和消费数据的地方 对数据 进行 处理)
class DataBuffer{
//存储数据的容器(我们默认 每次交互的数据 仅是 10 个)chick[] chicks = new chick[10];//当前 数据的个数int num = 0;public synchronized void producermethod(chick temp) throws InterruptedException {
//如果当前 数据的个数 满足十个 那么消费者 就要(消费)处理 数据!if(num == chicks.length){
//生产者 就需要 处于 等待状态了System.out.println("小鸡已满十个!等会儿再做!");this.wait();}//如果 不满足 十个 数据,那么生产者 就需要 往缓冲区 里面 扔数据chicks[num] = temp;//也就是说 我们 存储的 这个 数目 就是这样存。System.out.println("当前待消费的小鸡:"+(num+1)+"个");num++;this.notifyAll();}public synchronized chick consumermethod() throws InterruptedException {
//如果已经无法消费了,也就是说 十个小鸡我们都吃了,那么就让其 处于等待状态!然后生产者自销if(num == 0){
System.out.println("我草,小鸡让我吃完了!");this.wait();}//没有 小鸡num--;System.out.println("当前小鸡剩余:"+(num+1)+"个!");this.notifyAll();return chicks[num];}}
- 输出结果
生产出第:1只鸡!
当前待消费的小鸡:1个
生产出第:2只鸡!
当前待消费的小鸡:2个
生产出第:3只鸡!
当前待消费的小鸡:3个
生产出第:4只鸡!
当前待消费的小鸡:4个
生产出第:5只鸡!
当前待消费的小鸡:5个
生产出第:6只鸡!
当前待消费的小鸡:6个
生产出第:7只鸡!
当前待消费的小鸡:7个
生产出第:8只鸡!
当前待消费的小鸡:8个
生产出第:9只鸡!
当前待消费的小鸡:9个
生产出第:10只鸡!
当前待消费的小鸡:10个
生产出第:11只鸡!
小鸡已满十个!等会儿再做!
当前小鸡剩余:10个!
当前待消费的小鸡:10个
消费掉第:9只鸡!
生产出第:12只鸡!
当前小鸡剩余:10个!
消费掉第:10只鸡!
当前待消费的小鸡:10个
生产出第:13只鸡!
当前小鸡剩余:10个!
消费掉第:11只鸡!
当前待消费的小鸡:10个
生产出第:14只鸡!
当前小鸡剩余:10个!
消费掉第:12只鸡!
当前待消费的小鸡:10个
生产出第:15只鸡!
当前小鸡剩余:10个!
消费掉第:13只鸡!
当前待消费的小鸡:10个
生产出第:16只鸡!
当前小鸡剩余:10个!
消费掉第:14只鸡!
当前待消费的小鸡:10个
生产出第:17只鸡!
当前小鸡剩余:10个!
消费掉第:15只鸡!
当前待消费的小鸡:10个
生产出第:18只鸡!
当前小鸡剩余:10个!
消费掉第:16只鸡!
当前待消费的小鸡:10个
生产出第:19只鸡!
当前小鸡剩余:10个!
消费掉第:17只鸡!
当前待消费的小鸡:10个
生产出第:20只鸡!
当前小鸡剩余:10个!
消费掉第:18只鸡!
当前待消费的小鸡:10个
生产出第:21只鸡!
当前小鸡剩余:10个!
消费掉第:19只鸡!
当前待消费的小鸡:10个
生产出第:22只鸡!
当前小鸡剩余:10个!
消费掉第:20只鸡!
当前待消费的小鸡:10个
生产出第:23只鸡!
当前小鸡剩余:10个!
消费掉第:21只鸡!
当前待消费的小鸡:10个
生产出第:24只鸡!
当前小鸡剩余:10个!
消费掉第:22只鸡!
当前待消费的小鸡:10个
生产出第:25只鸡!
当前小鸡剩余:10个!
消费掉第:23只鸡!
当前待消费的小鸡:10个
生产出第:26只鸡!
当前小鸡剩余:10个!
消费掉第:24只鸡!
当前待消费的小鸡:10个
生产出第:27只鸡!
当前小鸡剩余:10个!
消费掉第:25只鸡!
当前待消费的小鸡:10个
生产出第:28只鸡!
小鸡已满十个!等会儿再做!
当前小鸡剩余:10个!
消费掉第:26只鸡!
当前待消费的小鸡:10个
生产出第:29只鸡!
当前小鸡剩余:10个!
消费掉第:27只鸡!
当前待消费的小鸡:10个
生产出第:30只鸡!
当前小鸡剩余:10个!
消费掉第:28只鸡!
当前待消费的小鸡:10个
生产出第:31只鸡!
当前小鸡剩余:10个!
消费掉第:29只鸡!
当前待消费的小鸡:10个
生产出第:32只鸡!
当前小鸡剩余:10个!
消费掉第:30只鸡!
当前待消费的小鸡:10个
生产出第:33只鸡!
当前小鸡剩余:10个!
消费掉第:31只鸡!
当前待消费的小鸡:10个
生产出第:34只鸡!
当前小鸡剩余:10个!
消费掉第:32只鸡!
当前待消费的小鸡:10个
生产出第:35只鸡!
当前小鸡剩余:10个!
消费掉第:33只鸡!
当前待消费的小鸡:10个
生产出第:36只鸡!
当前小鸡剩余:10个!
消费掉第:34只鸡!
当前待消费的小鸡:10个
生产出第:37只鸡!
当前小鸡剩余:10个!
消费掉第:35只鸡!
当前待消费的小鸡:10个
生产出第:38只鸡!
当前小鸡剩余:10个!
消费掉第:36只鸡!
当前待消费的小鸡:10个
生产出第:39只鸡!
当前小鸡剩余:10个!
消费掉第:37只鸡!
当前待消费的小鸡:10个
生产出第:40只鸡!
当前小鸡剩余:10个!
消费掉第:38只鸡!
当前待消费的小鸡:10个
生产出第:41只鸡!
当前小鸡剩余:10个!
消费掉第:39只鸡!
当前待消费的小鸡:10个
生产出第:42只鸡!
当前小鸡剩余:10个!
消费掉第:40只鸡!
当前待消费的小鸡:10个
生产出第:43只鸡!
当前小鸡剩余:10个!
消费掉第:41只鸡!
当前待消费的小鸡:10个
生产出第:44只鸡!
当前小鸡剩余:10个!
消费掉第:42只鸡!
当前待消费的小鸡:10个
生产出第:45只鸡!
当前小鸡剩余:10个!
消费掉第:43只鸡!
当前待消费的小鸡:10个
生产出第:46只鸡!
当前小鸡剩余:10个!
消费掉第:44只鸡!
当前待消费的小鸡:10个
生产出第:47只鸡!
当前小鸡剩余:10个!
消费掉第:45只鸡!
当前待消费的小鸡:10个
生产出第:48只鸡!
当前小鸡剩余:10个!
消费掉第:46只鸡!
当前待消费的小鸡:10个
生产出第:49只鸡!
当前小鸡剩余:10个!
消费掉第:47只鸡!
当前待消费的小鸡:10个
生产出第:50只鸡!
当前小鸡剩余:10个!
消费掉第:48只鸡!
当前待消费的小鸡:10个
生产出第:51只鸡!
当前小鸡剩余:10个!
消费掉第:49只鸡!
当前待消费的小鸡:10个
生产出第:52只鸡!
当前小鸡剩余:10个!
消费掉第:50只鸡!
当前待消费的小鸡:10个
生产出第:53只鸡!
当前小鸡剩余:10个!
消费掉第:51只鸡!
当前待消费的小鸡:10个
生产出第:54只鸡!
当前小鸡剩余:10个!
消费掉第:52只鸡!
当前待消费的小鸡:10个
生产出第:55只鸡!
当前小鸡剩余:10个!
消费掉第:53只鸡!
当前待消费的小鸡:10个
生产出第:56只鸡!
当前小鸡剩余:10个!
消费掉第:54只鸡!
当前待消费的小鸡:10个
生产出第:57只鸡!
当前小鸡剩余:10个!
消费掉第:55只鸡!
当前待消费的小鸡:10个
生产出第:58只鸡!
当前小鸡剩余:10个!
消费掉第:56只鸡!
当前待消费的小鸡:10个
生产出第:59只鸡!
当前小鸡剩余:10个!
消费掉第:57只鸡!
当前待消费的小鸡:10个
生产出第:60只鸡!
当前小鸡剩余:10个!
消费掉第:58只鸡!
当前待消费的小鸡:10个
生产出第:61只鸡!
当前小鸡剩余:10个!
消费掉第:59只鸡!
当前待消费的小鸡:10个
生产出第:62只鸡!
当前小鸡剩余:10个!
消费掉第:60只鸡!
当前待消费的小鸡:10个
生产出第:63只鸡!
当前小鸡剩余:10个!
消费掉第:61只鸡!
当前待消费的小鸡:10个
生产出第:64只鸡!
当前小鸡剩余:10个!
当前待消费的小鸡:10个
生产出第:65只鸡!
小鸡已满十个!等会儿再做!
消费掉第:62只鸡!
当前小鸡剩余:10个!
消费掉第:63只鸡!
当前待消费的小鸡:10个
生产出第:66只鸡!
当前小鸡剩余:10个!
消费掉第:64只鸡!
当前待消费的小鸡:10个
生产出第:67只鸡!
当前小鸡剩余:10个!
消费掉第:65只鸡!
当前待消费的小鸡:10个
生产出第:68只鸡!
当前小鸡剩余:10个!
消费掉第:66只鸡!
当前待消费的小鸡:10个
生产出第:69只鸡!
当前小鸡剩余:10个!
消费掉第:67只鸡!
当前待消费的小鸡:10个
生产出第:70只鸡!
当前小鸡剩余:10个!
消费掉第:68只鸡!
当前待消费的小鸡:10个
生产出第:71只鸡!
当前小鸡剩余:10个!
消费掉第:69只鸡!
当前待消费的小鸡:10个
生产出第:72只鸡!
当前小鸡剩余:10个!
消费掉第:70只鸡!
当前待消费的小鸡:10个
生产出第:73只鸡!
当前小鸡剩余:10个!
消费掉第:71只鸡!
当前待消费的小鸡:10个
生产出第:74只鸡!
当前小鸡剩余:10个!
消费掉第:72只鸡!
当前待消费的小鸡:10个
生产出第:75只鸡!
当前小鸡剩余:10个!
消费掉第:73只鸡!
当前待消费的小鸡:10个
生产出第:76只鸡!
当前小鸡剩余:10个!
消费掉第:74只鸡!
当前待消费的小鸡:10个
生产出第:77只鸡!
当前小鸡剩余:10个!
消费掉第:75只鸡!
当前待消费的小鸡:10个
生产出第:78只鸡!
当前小鸡剩余:10个!
消费掉第:76只鸡!
当前待消费的小鸡:10个
生产出第:79只鸡!
当前小鸡剩余:10个!
消费掉第:77只鸡!
当前待消费的小鸡:10个
生产出第:80只鸡!
当前小鸡剩余:10个!
消费掉第:78只鸡!
当前待消费的小鸡:10个
生产出第:81只鸡!
当前小鸡剩余:10个!
消费掉第:79只鸡!
当前待消费的小鸡:10个
生产出第:82只鸡!
当前小鸡剩余:10个!
消费掉第:80只鸡!
当前待消费的小鸡:10个
生产出第:83只鸡!
当前小鸡剩余:10个!
消费掉第:81只鸡!
当前待消费的小鸡:10个
生产出第:84只鸡!
当前小鸡剩余:10个!
消费掉第:82只鸡!
当前待消费的小鸡:10个
生产出第:85只鸡!
当前小鸡剩余:10个!
消费掉第:83只鸡!
当前待消费的小鸡:10个
生产出第:86只鸡!
当前小鸡剩余:10个!
消费掉第:84只鸡!
当前待消费的小鸡:10个
生产出第:87只鸡!
当前小鸡剩余:10个!
消费掉第:85只鸡!
当前待消费的小鸡:10个
生产出第:88只鸡!
当前小鸡剩余:10个!
消费掉第:86只鸡!
当前待消费的小鸡:10个
生产出第:89只鸡!
当前小鸡剩余:10个!
消费掉第:87只鸡!
当前待消费的小鸡:10个
生产出第:90只鸡!
当前小鸡剩余:10个!
消费掉第:88只鸡!
当前待消费的小鸡:10个
生产出第:91只鸡!
当前小鸡剩余:10个!
消费掉第:89只鸡!
当前待消费的小鸡:10个
生产出第:92只鸡!
当前小鸡剩余:10个!
消费掉第:90只鸡!
当前待消费的小鸡:10个
生产出第:93只鸡!
当前小鸡剩余:10个!
消费掉第:91只鸡!
当前待消费的小鸡:10个
生产出第:94只鸡!
当前小鸡剩余:10个!
消费掉第:92只鸡!
当前待消费的小鸡:10个
生产出第:95只鸡!
当前小鸡剩余:10个!
消费掉第:93只鸡!
当前待消费的小鸡:10个
生产出第:96只鸡!
当前小鸡剩余:10个!
消费掉第:94只鸡!
当前待消费的小鸡:10个
生产出第:97只鸡!
当前小鸡剩余:10个!
消费掉第:95只鸡!
当前待消费的小鸡:10个
生产出第:98只鸡!
当前小鸡剩余:10个!
消费掉第:96只鸡!
当前待消费的小鸡:10个
生产出第:99只鸡!
当前小鸡剩余:10个!
消费掉第:97只鸡!
当前待消费的小鸡:10个
生产出第:100只鸡!
当前小鸡剩余:10个!
消费掉第:98只鸡!
当前待消费的小鸡:10个
当前小鸡剩余:10个!
消费掉第:99只鸡!
当前小鸡剩余:9个!
消费掉第:8只鸡!
当前小鸡剩余:8个!
消费掉第:7只鸡!
所有鸡生产完毕!
当前小鸡剩余:7个!
消费掉第:6只鸡!
当前小鸡剩余:6个!
消费掉第:5只鸡!
当前小鸡剩余:5个!
消费掉第:4只鸡!
当前小鸡剩余:4个!
消费掉第:3只鸡!
当前小鸡剩余:3个!
消费掉第:2只鸡!
当前小鸡剩余:2个!
消费掉第:1只鸡!
当前小鸡剩余:1个!
消费掉第:0只鸡!
所有鸡消费完毕!
我们可以看到 线程之间基本上 是完成了 通讯。
"线程协作" 成功!!!
成功的关键点:
- wait() 方法
- notifyAll() 方法 —— 会唤醒该对象 所有 被 wait() 方法 等待的 线程。
为什么用 notifyAll() 呢 ?因为我们 必须时刻的 保证 两个线程 是清醒的!
举个例子:当 生产者 不需要生产的时候,消费者 的那条线程 之前消耗过快。导致 已经 wait() 挂起!那 这个时候 线程执行哪个呢? 你会发现 生产者 又开始 执行了。因为 生产者 不需要生产的时候 被 notify 又再次唤醒了。但是 消费者 那条 线程 可能就一直无法被唤醒!所以 这里使用的 是 notifyAll()。