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日

悬赏问题

  • ¥30 求一段fortran代码用IVF编译运行的结果
  • ¥15 深度学习根据CNN网络模型,搭建BP模型并训练MNIST数据集
  • ¥15 lammps拉伸应力应变曲线分析
  • ¥15 C++ 头文件/宏冲突问题解决
  • ¥15 用comsol模拟大气湍流通过底部加热(温度不同)的腔体
  • ¥50 安卓adb backup备份子用户应用数据失败
  • ¥20 有人能用聚类分析帮我分析一下文本内容嘛
  • ¥15 请问Lammps做复合材料拉伸模拟,应力应变曲线问题
  • ¥30 python代码,帮调试,帮帮忙吧
  • ¥15 #MATLAB仿真#车辆换道路径规划