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 PADS Logic 原理图
  • ¥15 PADS Logic 图标
  • ¥15 电脑和power bi环境都是英文如何将日期层次结构转换成英文
  • ¥20 气象站点数据求取中~
  • ¥15 如何获取APP内弹出的网址链接
  • ¥15 wifi 图标不见了 不知道怎么办 上不了网 变成小地球了
  • ¥50 STM32单片机传感器读取错误
  • ¥15 (关键词-阻抗匹配,HFSS,RFID标签天线)
  • ¥15 机器人轨迹规划相关问题
  • ¥15 word样式右侧翻页键消失