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

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形成的临界区可以被其他线程进入。
    然后,进一步分析,就可以得到答案了。

    评论
    解决 1 无用
    打赏 举报
查看更多回答(2条)

相关推荐 更多相似问题