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" 这句话有时候打印三次,有时候打印一次,很明显验证了我的结论

原文地址:https://www.cnblogs.com/lvcai/p/13576317.html