• JUC 并发编程--07 阻塞队列版本的 生产者消费者(不使用synchronized和 lock),也有一些疑惑,最终解惑


    直接上代码: 前提是你已经 熟悉了原子类,volatile,和阻塞队列

    public class JucPCdemo03 {
       /**
           * 阻塞队列的应用: 这里实现的生产者消费者,生产一个消费一个
           * 且,不使用 synchronized 和 lock锁
       */
        private volatile boolean flag = true;
        private static AtomicInteger atomicInteger = new AtomicInteger(0);
        private BlockingQueue<String> blockingQueue;
    
        public JucPCdemo03(BlockingQueue<String> blockingQueue) {
            this.blockingQueue = blockingQueue;
            System.out.println(blockingQueue.getClass().getName());
        }
    
        //生产方法
        public void producer() throws InterruptedException {
            String data = null;
            boolean result;
            while(flag){
                data = atomicInteger.incrementAndGet()+"";
                result = blockingQueue.offer(data, 2, TimeUnit.SECONDS);
                if(result){
                    System.out.println(Thread.currentThread().getName() + "--生产者--添加队列成功--data:" + data);
                }else{
                    System.out.println(Thread.currentThread().getName() + "--生产者--超出等待时间, 退出等待");
                }
                //我在这里有疑惑? : 你能帮我解决么?
                // 这里睡1秒,不能少,因为 atomicInteger加1的操作是原子的,加入阻塞队列的操作是并发的,会导致同一时间内,有多个元素加入到了阻塞队列中,返回都是true,即使规定阻塞队列容量为1, 
                // 所以这里的疑惑是: 阻塞队列容量为1, 并发情况下,却多个数据都加入队列成功了?为什么
                TimeUnit.SECONDS.sleep(1);
            }
    
            System.out.println();
            System.out.println();
            System.out.println();
            System.out.println("生产者停止生产了");
        }
        //消费方法
        public void consumer() throws InterruptedException {
            String data = null;
            while(flag){
                data = blockingQueue.poll(2, TimeUnit.SECONDS);
                if(null == data || "".equals(data)){
                    System.out.println(Thread.currentThread().getName() + "--消费者--超出等待时间.退出等待,消费停止");
                    flag = false;
                    return;
                }else{
                    System.out.println(Thread.currentThread().getName() + "--消费者--消费成功,消费的数据为: data:" + data);
                }
            }
            System.out.println();
            System.out.println();
            System.out.println();
            System.out.println("消费者停止消费了");
        }
        public void stop(){
            flag = false;
        }
        
        
        public static void main(String[] args) throws InterruptedException {
            JucPCdemo03 jucPCdemo03 = new JucPCdemo03(new ArrayBlockingQueue<>(1));
    
            new Thread(()->{
                try {
                    jucPCdemo03.producer();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            },"生产者线程启动").start();
    
            new Thread(()->{
                try {
                    jucPCdemo03.consumer();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            },"消费者线程启动").start();
    
            TimeUnit.SECONDS.sleep(5);
            jucPCdemo03.stop();
        }
    }
    

    运行结果:

    如果把生产者的 睡一秒, 注释掉, 会是另一种结果, 生产者生产的data 都很大,是因为一直再while循环中,不停的自增, 但是同时3个数据加入队列成功,可是队列的容量设置是1啊, 这个结果让我有些疑惑, 你能帮我解惑么?

    后来想到: 阻塞队列类本身是juc包下的, 肯定是原子性操作的, 所以他的容量前后都是始终为1, 是因为 "生产者线程启动--生产者--添加队列成功--data:269209" 这句话打印,这里并发打印了, 所以给我看到的假象多个数据都加入阻塞队列成功了, 于是验证: 加一行代码,

    运行结果为: 队列容量始终为1, "生产者线程启动--生产者--添加队列成功--data:269209" 这句话有时候打印三次,有时候打印一次,很明显验证了我的结论

  • 相关阅读:
    java编辑器eclipse如何更改jdk版本
    java 获取实体类对象属性值的方法
    java 时间处理
    java file的一些方法
    java中的包装类与装箱拆箱定义
    java中的分支
    java中的循环
    冒泡排序法
    HDFS数据迁移解决方案之DistCp工具的巧妙使用
    HDFS数据迁移解决方案之DistCp工具的巧妙使用
  • 原文地址:https://www.cnblogs.com/lvcai/p/13576317.html
Copyright © 2020-2023  润新知