zoukankan      html  css  js  c++  java
  • 使用阻塞队列实现生产者消费者问题

      相比Synchronized+wait()+notify()  和  Lock(Condition)+await()+signal() 的方式控制多线程之间的阻塞和唤醒,使用阻塞队列BlockingQueue更简单,程序员不需要花精力去关心什么时候需要阻塞线程,什么时候需要唤醒线程,一起交给BlockingQueue

      使用BlockingQueue的代码示例:

    1.资源类代码,内部有生产方法和消费方法,数据都存在阻塞队列中,使用阻塞队列的offer()和poll()插入和移除数据

    public class Source{//资源类
        private volatile boolean flag = true;//控制标志,true:生产和消费,false:不生产也不消费
        private AtomicInteger atomicInteger = new AtomicInteger(0);//原子类,避免写覆盖
        private BlockingQueue<String> blockingDeque = null;//阻塞对列
    
        public Source(BlockingQueue blockingDeque) {
            this.blockingDeque = blockingDeque;
        }
    
        /**
         * 生产数据
         * @author yang yajun
         * @date 2020/12/26 22:25
         * @Description: TODO
         */
        public void prod() throws InterruptedException {
    
            String data = null;
            boolean offer = false;
            while (flag){
                data = atomicInteger.incrementAndGet()+"";
                //插入数据,对列满了的话,就等2秒,如果还不行就返回false
                offer = blockingDeque.offer(data, 2L, TimeUnit.SECONDS);
                if(offer) {
                    System.out.println(Thread.currentThread().getName()+"生产成功"+data);
                }else {
                    System.out.println(Thread.currentThread().getName()+"2秒后生产失败");
                }
            }
            System.out.println(Thread.currentThread().getName()+"flag=false,停止生产");
        }
        /**
         * 消费数据
         * @author yang yajun
         * @date 2020/12/26 22:29
         * @Description: TODO
         */
        public void consumer() throws InterruptedException {
    
            String data = null;
            while (flag){
                //移除数据,对列为空的话,就等2秒,如果还不行就返回null
                data = blockingDeque.poll(2L, TimeUnit.SECONDS);
                if(data==null) {
    //                flag=false;
                    System.out.println(Thread.currentThread().getName()+"2秒后,获取数据失败");
                }else
                    System.out.println(Thread.currentThread().getName()+"获取数据成功"+data);
    
            }
            
        }
        /**
         * 对列停止工作
         * @author yang yajun
         * @date 2020/12/26 22:29
         * @Description: TODO
         */
        public void stop() {
            flag = false;
        }
    }

    2.主线程代码示例,启2个线程,分别调用资源类中的生产方法和消费方法,阻塞队列从构造器传入,队列界值设为3

    /**
     * 生产者消费者的高级版,BlockingQueue
     * @author yang yajun
     * @date 2020/12/2621:34
     * @Description: TODO
     */
    public class ProdConsumerBlockingQ {
        public static void main(String[] arg0) throws InterruptedException {
            BlockingQueue<String> blockingDeque = new ArrayBlockingQueue<>(3);
            Source source = new Source(blockingDeque);
    
            new Thread(()->{
                try {
                    source.prod();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
    
            new Thread(()->{
                try {
                    source.consumer();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
            TimeUnit.SECONDS.sleep(3);//主线程3秒后,停止阻塞队列工作
            System.out.println();
            System.out.println();
            System.out.println();
            System.out.println("停止");
            source.stop();
        }
    }

    注意:上面的代码有点漏洞,因为,在主线程执行stop方法后,阻塞队列里可能还有数据没被消费,看下面执行结果,可以看到有数据被生产了,但3732037321、37322没有被消费

    Thread-0生产成功37316
    Thread-0生产成功37317
    Thread-0生产成功37318
    Thread-1获取数据成功37316
    Thread-1获取数据成功37317
    Thread-1获取数据成功37318
    Thread-0生产成功37319
    Thread-0生产成功37320
    Thread-0生产成功37321
    Thread-0生产成功37322
    
    
    
    停止
    Thread-1获取数据成功37319
    Thread-02秒后生产失败
    Thread-0flag=false,停止生产

    要想保证队列中的数据被完全消费,其实好解决,就在消费方法中循环阻塞队列界值的次数,每次都调用poll()【不加时间参数的方法】就可以了

  • 相关阅读:
    set使用
    css盒子模型详解一
    列表页调用当前栏目的子类织梦标签
    织梦如何在导航栏下拉菜单中调用当前栏目子类
    HDU1812
    BZOJ1485: [HNOI2009]有趣的数列
    组合数学学习笔记
    Full_of_Boys训练2总结
    Full_of_Boys训练1总结
    FFT算法学习笔记
  • 原文地址:https://www.cnblogs.com/yayin/p/14194796.html
Copyright © 2011-2022 走看看