Faxon 2021-12-27 11:12 采纳率: 100%
浏览 28
已结题

Java生产者和消费者多线程问题

下面是一个线程安全的消费者、生产者实现,i 为共享变量,i 为 1 时消费,i 为 0 时生产;
但写完我有两个问题:

1. 在本地运行时,为什么使用 this.notify() 会出现运行一段时间就卡住了,像死锁一样。而用this.notifyAll() 就没有问题?
2. 为什么主线程没有使用join、sleep的方法,在启动完其他线程后变为阻塞状态,而不是结束?

// 多线程环境下的生产者和消费者
public class ThreadTest {

    volatile Integer i = 0;

    private synchronized void add() {
        while (i > 0) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("add: " + ++i);
        // TODO 问题1:这里用 this.notify() 运行一会就卡住,像死锁一样,不知道为什么?
        this.notifyAll();
    }

    private synchronized void reduce() {
        while (i < 1) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("red: " + --i);
         // TODO 问题1:这里用 this.notify() 运行一会就卡住,像死锁一样,不知道为什么?
        this.notifyAll();
    }


    public static void main(String[] args) throws InterruptedException {
        ThreadTest test = new ThreadTest();

        Runnable reduceR = () -> {
            while (true) {
                test.reduce();
            }
        };
        Thread reduceT1 = new Thread(reduceR);
        Thread reduceT2 = new Thread(reduceR);
        Thread reduceT3 = new Thread(reduceR);

        Runnable addR = () -> {
            while (true) {
                test.add();
            }
        };
        Thread addT1 = new Thread(addR);

        reduceT1.start();
        reduceT2.start();
        reduceT3.start();
        addT1.start();
        // TODO 问题2:主线程没有用sleep、join等方法, 应该到这就结束了,但实际中没有,而是阻塞状态,为什么?
    }

}

  • 写回答

3条回答 默认 最新

  • 冰思雨 2021-12-27 11:46
    关注

    notify 方法,调用一次只能唤醒一个线程,但是,楼主开启了4个线程,当 reduce 线程调用 notify 唤醒一个线程时,很有可能唤醒的是另外的reduce线程,而不是 add 线程,这时,另外的 reduce 线程进入自旋循环中,继续等等 i 的变化,不会进行额外的 notify 操作。

    如果上面的描述可以理解的话:

    判断 i 的值是否满足条件,为什么使用 while 自旋循环,而不使用 if 语句来进行判断?
    如果你理解了为什么使用 while 循环,就不难理解为什么要使用 notifyAll 方法进行唤醒了。
    提示一下,wait方法在被调用时,会阻塞当前线程,同时释放锁,造成synchronized形成的临界区可以被其他线程进入。
    然后,进一步分析,就可以得到答案了。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(2条)

报告相同问题?

问题事件

  • 系统已结题 1月4日
  • 已采纳回答 12月27日
  • 创建了问题 12月27日

悬赏问题

  • ¥15 Attention is all you need 的代码运行
  • ¥15 一个服务器已经有一个系统了如果用usb再装一个系统,原来的系统会被覆盖掉吗
  • ¥15 使用esm_msa1_t12_100M_UR50S蛋白质语言模型进行零样本预测时,终端显示出了sequence handled的进度条,但是并不出结果就自动终止回到命令提示行了是怎么回事:
  • ¥15 前置放大电路与功率放大电路相连放大倍数出现问题
  • ¥30 关于<main>标签页面跳转的问题
  • ¥80 部署运行web自动化项目
  • ¥15 腾讯云如何建立同一个项目中物模型之间的联系
  • ¥30 VMware 云桌面水印如何添加
  • ¥15 用ns3仿真出5G核心网网元
  • ¥15 matlab答疑 关于海上风电的爬坡事件检测