ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

用 “volatile 标记位的停止方法“ 不适合的场景

2021-08-18 08:00:18  阅读:226  来源: 互联网

标签:场景 Producer Thread 标记 storage volatile new Consumer public


 

package com.mzj.thread.interrupt;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

/**
 * 用 “volatile 标记位的停止方法“ 不适合的场景
 *
 * @author muzhongjiang 2021-08-12
 **/
public class VolatileCanStop {

    public static void main(String[] args) throws InterruptedException {
        ArrayBlockingQueue<Integer> storage = new ArrayBlockingQueue<>(8);
        Producer producer = new Producer(storage);
        Thread producerThread = new Thread(producer);
        producerThread.start();

        Thread.sleep(500);
        Consumer consumer = new Consumer(storage);
        while (consumer.needMoreNums()) {
            System.out.println(consumer.storage.take() + "被消费了");
            Thread.sleep(100);
        }

        System.out.println("消费者不需要更多数据了。");

        /**
         * 一旦Consumer不需要更多数据了,我们应该让Producer也停下来,但是实际情况却停不下来。
         * 当消费者不再需要数据,就会将 canceled 的标记位设置为 true,理论上此时生产者会跳出 while 循环,并打印输出“生产者运行结束”。
         * 然而尽管已经把 canceled 设置成 true,在某种情况下生产者仍然没有停止:生产者在执行 storage.put(num) 时发生阻塞,在它被叫醒之前是没有办法进入下一次while判断 canceled 的值的,
         * 所以在这种情况下用 volatile 是没有办法让生产者停下来的,
         * 相反如果用 interrupt 语句来中断,即使生产者处于阻塞状态,仍然能够感受到中断信号(因为put内部使用了await,会抛InterruptedException)。
         * */
        producer.canceled = true;// <<<<<<<<<<<<<<<<<<<<<<<<<<<
        System.out.println(producer.canceled);
    }

}

class Producer implements Runnable {
    public volatile boolean canceled = false;
    public BlockingQueue<Integer> storage;

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

    @Override
    public void run() {
        int num = 0;
        try {
            while (num <= 100000 && !canceled) {
                if (num % 50 == 0) {
                    storage.put(num);
                    System.out.println(num + "是50的倍数,被放到仓库中了。");
                }
                num++;
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            System.out.println("生产者结束运行");
        }

    }

}

class Consumer {

    public BlockingQueue<Integer> storage;

    public Consumer(BlockingQueue<Integer> storage) {
        this.storage = storage;
    }

    public boolean needMoreNums() {
        if (Math.random() > 0.97) {
            return false;
        }
        return true;
    }

}

 

标签:场景,Producer,Thread,标记,storage,volatile,new,Consumer,public
来源: https://www.cnblogs.com/muzhongjiang/p/15155032.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有