在视屏中说使用Volatile不能停止线程,但是我加上一个休眠之后能够停止,请问为什么?

来源:5-11 错误停止2

qq_慕数据1338854

2020-01-19

老师,请问为什么我再WrongWayVolatileCantStop.java里面的Producer的run方法里面加上一个休眠。好像是能够正常停止线程,请问为什么?

class Producer implements Runnable{

    public volatile boolean canceled = false;
    BlockingQueue storage;

    public Producer(BlockingQueue storage) {
        this.storage = storage;
    }

    @Override
    public void run() {
        int num = 0;
        try {
            while (num <= 100000 && !canceled) {
                if (num % 100 == 0) {
                    storage.put(num);//放到仓库中
                    System.out.println(num + "是100的倍数,被放到仓库中了。");
                }
                num++;
                //加上这句话,就能停止线程
                Thread.sleep(1);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            System.out.println("生产者结束运行");
        }
    }
}
写回答

3回答

慕婉清0327545

2020-04-25

我觉得是加上Thread.sleep(1)休眠之后,虽然看起来1millis时间很少,但是这个休眠是放在while循环里的,当生产者生产一个对象的时候,此时whil已经循环100次了,相当于每生产一个对象,就要休眠100millis。生产周期与消费周期巧好相等,所以仓库不会阻塞。也就是说每次循环都可以感知cancel的变化。

如果将消费者的消费周期设为300millis,即使Producer的run方法里面加上一个休眠,线程也不会正常停止。

Consumer consumer = new Consumer(storage);
while (consumer.needMoreNums()) {
    System.out.println(consumer.storage.take()+"被消费了");
    // 将休眠的时间从100改为300
    Thread.sleep(300);
}
System.out.println("消费者不需要更多数据了。");


0
0

qq_慕数据1338854

提问者

2020-01-19

老师不好意思,我不是很懂老师的解答。我自己试了一下把消费时间调大,也把仓库容量调小。这时候就会出现停止不了线程的情况。我觉得是因为在Producer里的run方法加上一个一定时间的阻塞,导致仓库没有被塞满。所以生产者就不会进入休眠状态,这样volatile标记位还是有效的。请问这样理解对吗?

0
1
悟空
对的,加了sleep后,改变cancel的时候,生产者并不是停在put语句,所以就可以感知到cancel的变化
2020-01-19
共1条回复

悟空

2020-01-19

在睡眠的时候,CPU会尽量利用这段时间来同步所有的变量,所以就可以看到属性的变化。

0
0

线程八大核心+Java并发原理及企业级并发解决方案

完整的并发知识网络+丰富的工作内容分享+50余道并发高频面试题

2512 学习 · 939 问题

查看课程