当前位置: 代码迷 >> 综合 >> JavaThread 14 线程协作 → 管程法
  详细解决方案

JavaThread 14 线程协作 → 管程法

热度:62   发布时间:2023-11-24 13:47:14.0

6.2 线程协作


6.2.1 生产者消费模式

  • 应用场景:生产者和消费者 问题
  1. 假设仓库中只能存放一件产品,生产者将生产出来的产品放入仓库,消费者将仓库中的产品取走消费。

  2. 如果仓库中没有产品,则生产者将 产品放入仓库,否则停止生产并等待,直到仓库中的产品被消费者取走为止。

  3. 如果仓库中放有产品,则消费者可以将产品取走消费,否则停止消费并等待,直到仓库中再次放入产品位置。

在这里插入图片描述


6.2.2 线程通讯-分析

这是一个线程同步问题,生产者和消费者 共享一个资源,并且生产者和消费者 之间相互依赖,互为条件。

  • 对于生产者而言,没有生产产品之前,要通知消费者进行等待。而生产了产品之后,又必须马上通知消费者让它进行消费。
  • 对于消费者而言,在消费之后,要通知生产者,消费已结束。需要再次生产新的产品 供给自己消费。
  • 在生产者消费者问题中,仅仅 用 synchronized 是完全不够的!
  1. synchronized 只能阻止 并发更新同一个共享资源的问题,实现了 线程同步。

  2. synchronized 不能用来实现不同线程之间的消息传递(通信)<因为 其它线程 直接 处于阻塞状态,还 通讯 个 屁了 ~ ~ 所以才需要 wait() 方法 和 notifyAll() 方法>

方法名 作用
wait() 表示线程一直等待,直到其它线程通知你,才会解除等待状态,与 sleep 不同的是,它会释放锁!也就是可以实现 线程间的通讯。
wait(long timeout) 指定等待的毫秒数
notify() 唤醒一个处于等待状态的线程
notifyAll() 唤醒同一个对象上所有调用过 wait()方法的线程,优先级别高的线程优先调度

6.2.3 管程法

代码设计流程:

  1. 创建两个 事务,一个生产者事务,一个消费者事务

  2. 创建一个 数据缓冲区,用于 操作 数据

  3. 数据缓冲区里面,写两个 synchronized 方法 一个是生产者 处理数据的方法,一个是 消费者处理数据的方法。

  4. 创建 一个数据结构体,用来 说明我们要 处理的数据。

  5. 生产者事务里 会新建 很多的 该数据对象

  6. 消费者事务里 会释放 很多的 该数据对象

  7. 创建 一个 数据缓冲区的 数据存储器

  8. 生产者处理数据的方法 是接收 生产者事务 传递过来的 数据。并 判断 是否 继续接收。

  9. 消费者处理数据的方法 是接收的 数据 返回给 消费者事务,让消费者事务 进行 实质性的 消费!

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只鸡!
所有鸡消费完毕!

我们可以看到 线程之间基本上 是完成了 通讯。
"线程协作" 成功!!!

成功的关键点:

  1. wait() 方法
  2. notifyAll() 方法 —— 会唤醒该对象 所有 被 wait() 方法 等待的 线程。

为什么用 notifyAll() 呢 ?因为我们 必须时刻的 保证 两个线程 是清醒的!

举个例子:当 生产者 不需要生产的时候,消费者 的那条线程 之前消耗过快。导致 已经 wait() 挂起!那 这个时候 线程执行哪个呢? 你会发现 生产者 又开始 执行了。因为 生产者 不需要生产的时候 被 notify 又再次唤醒了。但是 消费者 那条 线程 可能就一直无法被唤醒!所以 这里使用的 是 notifyAll()。