java多线程-BlockingQueue(阻塞队列)

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

下图展示了如何通过阻塞队列来合作:
java多线程-BlockingQueue(阻塞队列)_第1张图片
线程1往阻塞队列中添加元素,而线程2从阻塞队列中移除元素

BlockingQueue 方法以四种形式出现,对于不能立即满足但可能在将来某一时刻可以满足的操作,这四种形式的处理方式不同:

  • 第一种是抛出一个异常。
  • 第二种是返回一个特殊值(null 或 false,具体取决于操作)。
  • 第三种是在操作可以成功前,无限期地阻塞当前线程。
  • 第四种是在放弃前只在给定的最大时间限制内阻塞。

下表中总结了这些方法:
java多线程-BlockingQueue(阻塞队列)_第2张图片

含有方法解释:

  • boolean add(E e)
    将指定元素插入此队列中,成功时返回 true,如果当前队列已满没有可用的空间,无法插入,则抛出 IllegalStateException。

  • boolean offer(E e)
    将指定元素插入此队列中,成功时返回 true,如果当前队列已满没有可用的空间,无法插入,则返回 false。

  • void put(E e)
    将指定元素插入此队列中,将等待可用的空间,进入阻塞状态。

  • boolean remove(Object o)
    从此队列中移除指定元素的单个实例。

  • E peek()
    获取但不移除此队列的头;如果此队列为空,则返回 null。

  • E element()
    获取但是不移除此队列的头。此方法与 peek 唯一的不同在于:此队列为空时将抛出一个异常。

  • E poll()
    获取并移除此队列的头,如果此队列为空,则返回 null。

  • E take()
    获取并移除此队列的头部,在元素变得可用之前一直等待(如果有必要)。

示例:

import java.util.concurrent.ArrayBlockingQueue;

/** * 测试双缓冲队列 FIFO(先进先出) */
public class CopyOfTestBlockingQueue {
    private int queueSize = 10;
    private ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<String>(queueSize);

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

    class Consumer extends Thread {

        @Override
        public void run() {
            consume();
        }

        private void consume() {
            while (true) {
                try {
                    String s = queue.take();    //获取并移除此队列的头部,在元素变得可用之前一直等待
                    System.out.println("从队列中取出:"+s+",队列剩余" + queue.size() + "个元素");
                    Thread.sleep((int)(Math.random()*1000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    class Producer extends Thread {
        int i = 0;
        @Override
        public void run() {
            produce();
        }

        private void produce() {
            while (true) {
                try {
                    queue.put("元素"+(++i));  //将指定的元素插入此队列的尾部,如果该队列已满,则等待可用的空间。
                    System.out.println("向队列中插入:元素"+i+",队列剩余空间:" + (queueSize - queue.size()));
                    Thread.sleep((int)(Math.random()*1000));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

结果:

从队列中取出:元素1,队列剩余0个元素
向队列中插入:元素1,队列剩余空间:10
向队列中插入:元素2,队列剩余空间:9
从队列中取出:元素2,队列剩余0个元素
向队列中插入:元素3,队列剩余空间:9
从队列中取出:元素3,队列剩余0个元素
从队列中取出:元素4,队列剩余0个元素
向队列中插入:元素4,队列剩余空间:10
向队列中插入:元素5,队列剩余空间:9
向队列中插入:元素6,队列剩余空间:8
从队列中取出:元素5,队列剩余1个元素
从队列中取出:元素6,队列剩余0个元素
向队列中插入:元素7,队列剩余空间:9
向队列中插入:元素8,队列剩余空间:8
向队列中插入:元素9,队列剩余空间:7
向队列中插入:元素10,队列剩余空间:6
从队列中取出:元素7,队列剩余3个元素
从队列中取出:元素8,队列剩余2个元素
向队列中插入:元素11,队列剩余空间:7

你可能感兴趣的:(多线程,队列)