Java_线程通信

发布时间:2024年01月12日

一、线程通信

首先,什么是线程通信呢?

  • 当多个线程共同操作共享资源时,线程间通过某种方式互相告知自己的状态,以相互协调,避免无效的资源挣抢。

线程通信的常见模式:是生产者与消费者模型

  • 生产者线程负责生成数据
  • 消费者线程负责消费生产者生成的数据
  • 注意:生产者生产完数据后应该让自己等待,通知其他消费者消费;消费者消费完数据之后应该让自己等待,同时通知生产者生成。

比如下面案例中,有3个厨师(生产者线程),两个顾客(消费者线程)。
在这里插入图片描述
接下来,我们先分析一下完成这个案例的思路

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();
        }
    }
}

在这里插入图片描述

只有拿锁对象调用上述方法才不会出Bug,否则一定会出问题,因为只有锁对象知道当前谁占据了它,然后谁需要等待,所以锁对象调用wait()方法就会把占据它的方法进行等待,锁对象调notify()方法就会把等待锁对象的那些方法唤醒

再写测试类,在测试类中,创建3个厨师线程对象,再创建2个顾客对象,并启动所有线程

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();
    }
}

执行上面代码,运行结果如下:你会发现多个线程相互协调执行,避免无效的资源挣抢。

厨师1做了一个肉包子~~
吃货2吃了:厨师1做的肉包子
厨师3做了一个肉包子~~
吃货2吃了:厨师3做的肉包子
厨师1做了一个肉包子~~
吃货1吃了:厨师1做的肉包子
厨师2做了一个肉包子~~
吃货2吃了:厨师2做的肉包子
厨师3做了一个肉包子~~
吃货1吃了:厨师3做的肉包子
......
文章来源:https://blog.csdn.net/qq_48083892/article/details/135450243
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。