并发编程-生产者消费者-阻塞队列版本-详解

个人建议还是把我之前写的几个版本生产者-消费者都了解一下,有利于加深对并发编程的理解
1.synchronzied版本-多生产者-多消费者-模型
2.Lock版本-多生产者-多消费者-模型
3.多生产-多消费-总结(生产一组,消费一组)

这个代码里面会有几个比较核心问题放在上边,在这里给大家解答一下:

使用阻塞队列的方式的好处
1.实现生产者和消费者进行解耦,作为开发者无需关心复杂的线程之间的通信(await,signal,signalAll等监视器方法),让开发者更加专注业务;
2.阻塞队列封装了线程之间的通信;

flag字段为什么要加生volatile关键字?
1.阻塞队列的方式,是没有Lock锁,也就是我们的 pro(生产方法) consu(消费方法)都是线程不安全的,也就无法通过锁的同步机制,实现共享变量的可见行;
2.volatile主要是对保证当一个线程修改了共享变量的时候,其他线程能够立刻能看见

为什么使用多个原子类?
1.资源类的共享方法没有使用锁的同步机制,所以必须要使用原子类(CAS)来保证多个线程操作count(计数器)的正确性;

**上代码 **
资源类

static class Resource {
        //这个flag控制 控制生产者消费者消息的运行;
        //为什么要加volatile,这是为了保证线程的可见行;
        //当有一个线程操作flag时,对于其他线程都是可见的;
        private volatile boolean flag = true;

        //为什么要用原子类,这是因为资源类的方法都没有使用Lock锁,这也就是说明 pro consu 生产,消费方法不是线程安全,
        // 当多个线程更新共享变量,会出现线程安全问题;
        private AtomicInteger count = new AtomicInteger();

        //使用阻塞队列来实现了 生产者和消费者的解耦合,也无需关心复杂的await,signal,signalAll等线程之间的通信;
        private BlockingQueue<String> queue;

        public Resource(BlockingQueue<String> queue) {
            this.queue = queue;
            System.out.println(queue.getClass().getName() + " 阻塞队列创建");
        }


        public void stop() {
            this.flag = false;
            System.out.println("BlockQueueProdConsu stop ....");
        }


        public void pro() throws Exception {
            int data;
            boolean res;
            while (flag) {
                //保证不会重复生产数据
                data = count.incrementAndGet();
                res = queue.offer(data + "", 2, TimeUnit.SECONDS);

                if (res) {
                    System.out.println(Thread.currentThread().getName() + "生产 数据" + data);
                } else {
                    System.out.println(Thread.currentThread().getName() + "生产 数据失败" + data);
                }
                Thread.sleep(1000);
            }
        }

        public void consu() throws Exception {
            String res = null;
            while (flag) {
                res = queue.poll(2, TimeUnit.SECONDS);
                if (res == null) {
                    System.out.println(Thread.currentThread().getName() + "消费 数据 失败");
                    System.out.println(Thread.currentThread().getName() + "消费者 退出");
                    break;
                }
                System.out.println(Thread.currentThread().getName() + "消费 数据 " + res);
            }
        }
    }

测试方法

public static void main(String[] args) throws InterruptedException {
        Resource resource = new Resource(new ArrayBlockingQueue<>(3));

        new Thread(() -> {
            try { resource.pro(); } catch (Exception e) { }
        },"生产者1").start();
        new Thread(() -> {
            try { resource.pro(); } catch (Exception e) { }
        },"生产者2").start();


        new Thread(() -> {
            try { resource.consu(); } catch (Exception e) { }
        },"消费者1").start();
        new Thread(() -> {
            try { resource.consu(); } catch (Exception e) { }
        },"消费者2").start();

        Thread.sleep(5000);
        resource.stop();

        System.out.println("主程序结束");
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值