阻塞队列ArrayBlockingQueue实现生产者消费者模型

阻塞队列图: 

        阻塞队列与普通队列的区别在于,当队列是空的时,从队列中获取元素的操作将会被阻塞,或者当队列是满时,往队列里添加元素的操作会被阻塞。试图从空的阻塞队列中获取元素的线程将会被阻塞,直到其他的线程往空的队列插入新的元素。同样,试图往已满的阻塞队列中添加新元素的线程同样也会被阻塞,直到其他的线程使队列重新变得空闲起来。

        有好几种阻塞队列,本文只用到了最常用的两个阻塞队列之一:ArrayBlockingQueue。

        ArrayBlockingQueue:基于数组实现的一个阻塞队列,在创建ArrayBlockingQueue对象时必须制定容量大小。并且可以指定公平性与非公平性,默认情况下为非公平的。

        阻塞队列的场景刚好符合操作系统中的生产者消费者模型,传统的生产者消费者问题中还要在特定位置实现wait()和signal()操作,不能颠倒顺序,比较繁琐。而jdk 5.0开始引入的这个java.util.concurrent包显然让生产者消费者问题得到很好的简化,全都自动完成了,wait(),signal()都不用写了,多好。

put():用来向队尾存入元素,如果队列满,则等待;

take():用来从队首取元素,如果队列为空,则等待;

       代码说明:

       线程采用继承Thread类重写run方法实现。

        Math.Random()产生一个0到1(不包括0和1)的随机浮点数,扩大10倍+1后结果就是产生一个1到10的随机整数,使得生产者每生产一个产品放入阻塞队列队尾(或者消费者从阻塞队列队首取走一个产品)后对应的线程会休眠1到10ms

import java.util.concurrent.ArrayBlockingQueue;

public class Test {
    private int queueSize = 10;//初始化阻塞队列长度为10
    private ArrayBlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(queueSize);

    public static void main(String[] args)  {
        Test test = new Test();
        Producer producer = test.new Producer();
        Consumer consumer = test.new Consumer();

        producer.start();
        consumer.start();
    }

    class Consumer extends Thread{

        @Override   //此注解用于检测是否重写了父类的run方法,如果下行的run单词写错编译器就会报红
        public void run() {
            consume();
        }

        private void consume() {
            int ran;//随机生成数1-10放在ran中
            while(true){
                try {
                    ran=(int)Math.random()*10+1;//产生1-10的随机数
                    queue.take();
                    System.out.println("从队列取走一个元素,队列剩余"+queue.size()+"个元素");
                    sleep(ran);//线程休眠产生的随机时间ran
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    class Producer extends Thread{
        @Override   
        public void run() {
            produce();
        }
        private void produce() {
            int ran;
            while(true){
                try {
                    ran=(int)Math.random()*10+1;
                    queue.put(1);
                    System.out.println("向队列插入一个元素,队列剩余空间:"+(queueSize-queue.size()));
                    sleep(ran);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

运行一下会发现不会出现程序挂起不运行的情况,这证实了阻塞队列是线程安全的,即不会出现生产者阻塞同时消费者阻塞的情况。

猜你喜欢

转载自blog.csdn.net/Zhongtongyi/article/details/105962443