用Concurrent包下的BlockingQueue阻塞队列实现生产者消费者模型

Concurrent包

java.util.concurrent包下主要包括5个部分(《Java并发编程的艺术》这书对这5个部分都有介绍,感兴趣的朋友可以去阅读):
①Collection集合类:包括并不限于ConcurrentHashMap,BlockingQueue等等。
②lock的实现类:ReentrantLock 类,读写锁,condition等。
③util类:如CountDownLatch,信号量Semaphore,Exchanger等
④atomic类:AtomicInteger,AtomicBoolean类等
⑤线程池相关:Excutor接口,ThreadPoolExcutor接口实现类等

类图结构:
在这里插入图片描述
脑图地址: http://www.xmind.net/m/tJy5。

阻塞队列

就是一个队列,实行FIFO的规则,然后当队列为空时,take()出队会阻塞直到其他线程调用入队操作才能继续出队操作。当队列满了的时候,put()入队会阻塞直到其他线程调用出队操作才能继续入队操作。

简单实现阻塞队列以及put()方法和take()方法

public class BlockingQueue {
    private Object[] queue;
    private int head;
    private int tail;
    private volatile int size;

    BlockingQueue(int length){
        head = 0;
        tail = 0;
        queue = new Object[length];
        size = 0;
    }
    public void put(Object obj) throws InterruptedException{
        synchronized (this){
            while(this.size == queue.length){
                this.wait();
            }
            //因为该测试程序是生产者的效率比消费者的效率要高得多,所以一般情况都是进入上面这个wait进行等待消费者消费
            //而消费者消费完后还要进行一些步骤才可以到达System.out语句,所以以防出现歧义,这里生产者线程睡眠一小段时间。
            Thread.sleep(10);
            
            queue[tail] = obj;
            size++;
            tail++;
            if(tail == queue.length){
                tail = 0;
            }
            this.notify();
        }
    }
    public Object take() throws InterruptedException{
        Object result;
        synchronized (this){
            while(this.size == 0){
                this.wait();
            }
            result = queue[head];
            head++;
            size--;
            if(head == queue.length){
                head = 0;
            }
            this.notify();
        }
        return result;
    }
}

生产者类

使用类实现Runnable方法创建线程。

public class Producer implements Runnable{
    private BlockingQueue bq;
    Producer(BlockingQueue blockingQueue){
        this.bq = blockingQueue;
    }
    @Override
    public void run() {
        for(int i = 0 ; i < 10 ; i++){
            Apple apple = new Apple(i);
            try {
                bq.put(apple);
                System.out.println("往队列里面放入id为"+ apple.getId()+"的苹果");
                //需要200毫秒生产一个苹果
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

消费者类

使用类继承Thread类的方法创建线程

public class Consumer extends Thread{
    private BlockingQueue bq;
    Consumer(BlockingQueue blockingQueue){
        this.bq = blockingQueue;
    }
    public void run(){
        for(int i = 0 ; i < 10 ; i++){
            try {
                Apple apple = (Apple) bq.take();
                System.out.println("拿到了id为"+apple.getId()+"的苹果来吃");
                //吃一个苹果需要1000毫秒
                Thread.sleep(4000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

测试

public class TestBlockingQueue {
    public static void main(String[] args) throws InterruptedException {
        BlockingQueue blockingQueue = new BlockingQueue(3);
        //实现Runnable接口的类需要先创建对象
        Producer producer = new Producer(blockingQueue);
        new Thread(producer).start();
        Thread.sleep(10);  //保证输出语句的顺序
        new Consumer(blockingQueue).start();
    }
}

结果

在这里插入图片描述
从结果可以看出:我们创建了长度为3的阻塞队列,因为我们的生产者效率是比消费者效率要高的,所以队列满了的情况时有发生。当队列满了的时候,结果呈现的是需要等待消费者线程吃掉一个苹果才能继续进行入苹果的操作。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值