java多线程实现生产者、消费者模式

本文介绍了生产者消费者问题的经典线程模型,阐述了生产者、消费者和缓冲区的概念,以及设置缓冲区带来的并发协作、解耦合和效率提升的好处。通过Java代码展示了使用Lock锁机制和阻塞队列(LinkedBlockingQueue)实现的解决方案,展示了如何在多线程环境下协调生产者和消费者的同步操作。
摘要由CSDN通过智能技术生成

简述

生产者和消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一存储空间,生产者向缓存区里生产数据,而消费者从缓存区里取出数据

什么是生产者?

  生产者指的是负责生产数据的模块。

什么是消费者?

  消费者指的是负责消费数据的模块。

什么是缓冲区?

   消费者不能直接使用生产者的数据,它们之间有个缓冲区。生产者将生产好的数据放入缓冲区,消费者从缓冲区取要处理的数据。

注:上面的的模块指的可能是:方法、对象、线程等。

缓冲区是实现并发协助的核心,设置缓冲区有几个好处:

1.实现线程的并发协作

  有了缓冲区以后,生产者线程只需往缓冲区里面放置数据,不需要管消费者消费的情况。同样,消费者只需要从缓冲区取数据处理,不需要管生产者生产的情况。 这样就从逻辑上实现了生  产者线程和消费者线程的分离。

2.解耦了生产者和消费者

  生产者不需要和消费者直接打交道。

3.解决忙闲不均,提高效率

  生产者生产数据慢时,缓冲区仍有数据,不影响消费者消费。消费者处理数据慢时,生产者仍然可以继续往缓冲区里面放置数据 。

代码实现

1 .使用 lock锁机制实现, 通过创建Lock对象,采用lock()加锁,unlock()解锁。


class Resource {
    private int num;
    private Lock reentrantLock = new ReentrantLock();
    private Condition condition =  reentrantLock.newCondition();

    //生产
    public void add(){
        //消费了再生产 不等于0时循坏等待
        reentrantLock.lock();
        try {
            while (num!=0){
                condition.await();
            }
            System.out.println(Thread.currentThread().getName()+"生产 +1");
            num++;
            condition.signalAll();//通知消费 唤醒所有wait状态的线程
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            reentrantLock.unlock();
        }
    }

    public void minus(){
        //生产了再消费 等于0时循坏等待
        reentrantLock.lock();
        try {
            while (num==0){
                condition.await();
            }
            System.out.println(Thread.currentThread().getName()+"消费 -1");
            num--;
            condition.signalAll();//通知消费 唤醒所有wait状态的线程
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            reentrantLock.unlock();
        }
    }
}
public class ProductionAndConsumer {

    public static void main(String[] args) {
        Resource resource = new Resource();
        for (int i = 1; i <6 ; i++) {
            new Thread(()->{
                resource.add();
            },"生产线程").start();
        }
        for (int i = 1; i <6 ; i++) {
            new Thread(()->{
                resource.minus();
            },"消费线程").start();
        }
    }

}

运行输出:

2.使用阻塞队列实现


public class ProductionAnDConsumerBlockingQueue {

    public static void main(String[] args) throws InterruptedException {
        Resource resource = new Resource(new LinkedBlockingQueue(10));
        new Thread(()->{
            try {
                resource.prod();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"prod").start();
        new Thread(()->{
            try {
                resource.consumer();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        },"consumer").start();



        TimeUnit.SECONDS.sleep(5);

        System.out.println("按下关闭开关,停止生产、消费");
        resource.stop();
    }
    static class Resource {
        ///生产开关
        private volatile boolean flag = true;
        private AtomicInteger num = new AtomicInteger();
        //阻塞队列
        private BlockingQueue queue = null;

        public Resource(BlockingQueue queue) {
            this.queue = queue;
        }
        /*
         *生产队列
         **/
        public void prod() throws InterruptedException {
            String temp  ;
            boolean offer;
            while (flag){
                temp =   num.incrementAndGet()+"";
                //生产模式开启
                offer = queue.offer(temp, 2l, TimeUnit.SECONDS);
               // if(offer){
                    System.out.println(Thread.currentThread().getName()+"生产成功,插入队列成功:"+temp);
//                }else {
//                    System.out.println("生产失败,插入队列失败:"+temp);
//                }
                //模拟业务操作耗时时间
                TimeUnit.SECONDS.sleep(1);
            }

            System.out.println("生产总开关关闭了 状态:"+flag);
        }


        /*
         * 消费队列
         **/
        public void consumer() throws InterruptedException{
            String poll;
            while (flag){
                poll = (String) queue.poll(2l, TimeUnit.SECONDS);
                if(poll==null||poll.equalsIgnoreCase("")){
                    System.out.println("等待超时,停止消费");
                    this.flag=false;
                    return;
                }
                System.out.println(Thread.currentThread().getName()+"消费成功"+poll);
            }
            System.out.println("消费队列检查到总开关关闭了 状态:"+flag);
        }


        public void stop(){
            this.flag=false;
        }
    }
}

运行输出

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值