Java BlockingQueue

时间:2020-01-09 10:36:25  来源:igfitidea点击:

Java BlockingQueue接口java.util.concurrent.BlockingQueue表示一个队列,该线程是线程安全的,可以将元素放入和取出元素。换句话说,多个线程可以同时从JavaBlockingQueue插入和获取元素,而不会引起任何并发问题。

术语"阻塞队列"来自Java'BlockingQueue'能够阻塞试图从队列中插入或者获取元素的线程的事实。例如,如果线程尝试采用元素,而队列中没有剩余元素,则可以阻塞线程,直到要采用元素为止。调用线程是否被阻塞取决于我们在" BlockingQueue"上调用的方法。稍后将详细说明不同的方法。

本文不会讨论如何在Java中自己实现" BlockingQueue"。如果我们对此感兴趣,请在我的理论性更高的Java并发教程中找到有关阻塞队列的文字。

BlockingQueue的使用

" BlockingQueue"通常用于使一个线程产生对象,而另一线程消耗该对象。

生产线程将继续生产新对象并将其插入到" BlockingQueue"中,直到队列达到其所包含内容的上限为止。换句话说,这是极限。如果阻塞队列达到其上限,则在尝试插入新对象时会阻塞生产线程。在使用线程将对象从队列中取出之前,它一直处于阻塞状态。

消费线程不断将对象从" BlockingQueue"中取出来进行处理。如果使用方线程试图将对象从空队列中取出,则使用方线程将被阻塞,直到产生方线程将对象放入队列中为止。

BlockingQueue方法

Java" BlockingQueue"接口具有4种不同的方法集,用于插入,删除和检查队列中的元素。如果无法立即执行所请求的操作,则每组方法的行为都会有所不同。

这4种不同的行为集意味着:

  • 引发异常:如果无法立即进行尝试的操作,则会引发异常。
  • 特殊值:如果无法立即尝试操作,则会返回一个特殊值(通常为true / false)。
  • 阻止:如果无法立即执行尝试的操作,则该方法调用将阻止直到成功。
  • 超时:如果无法立即进行尝试的操作,则该方法调用将一直阻塞直到成功,但等待时间不得长于给定的超时。返回一个特殊值,告诉操作是否成功(通常为true / false)。

无法将" null"插入到" BlockingQueue"中。如果我们尝试插入null,则BlockingQueue将抛出NullPointerException

也可以访问" BlockingQueue"内部的所有元素,而不仅仅是开始和结束的元素。例如,假设我们已将一个对象排队等待处理,但是应用程序决定取消该对象。然后,我们可以致电remove(o)删除队列中的特定对象。但是,这样做的效率不是很高,因此除非确实需要,否则不应使用这些" Collection"方法。

BlockingQueue实现

由于BlockingQueue是一个接口,因此我们需要使用其实现之一来使用它。 java.util.concurrent软件包具有BlockingQueue接口的以下实现:

  • ArrayBlockingQueue
  • 延迟队列
  • LinkedBlockingQueue
  • PriorityBlockingQueue
  • 同步队列

单击列表中的链接以了解有关每个实现的更多信息。

Java BlockingQueue示例

这是一个JavaBlockingQueue示例。该示例使用了BlockingQueue接口的ArrayBlockingQueue实现。

首先,使用" BlockingQueueExample"类,在单独的线程中启动" Producer"和" Consumer"。生产者将字符串插入共享的BlockingQueue中,而消费者则将它们取出。

public class BlockingQueueExample {

    public static void main(String[] args) throws Exception {

        BlockingQueue queue = new ArrayBlockingQueue(1024);

        Producer producer = new Producer(queue);
        Consumer consumer = new Consumer(queue);

        new Thread(producer).start();
        new Thread(consumer).start();

        Thread.sleep(4000);
    }
}

这是生产者类。请注意,它是如何在每个put()调用之间休眠一秒钟的。在等待队列中的对象时,这将导致"消费者"阻塞。

public class Producer implements Runnable{

    protected BlockingQueue queue = null;

    public Producer(BlockingQueue queue) {
        this.queue = queue;
    }

    public void run() {
        try {
            queue.put("1");
            Thread.sleep(1000);
            queue.put("2");
            Thread.sleep(1000);
            queue.put("3");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

这是"消费者"类。它只是从队列中取出对象,然后将它们打印到" System.out"。

public class Consumer implements Runnable{

    protected BlockingQueue queue = null;

    public Consumer(BlockingQueue queue) {
        this.queue = queue;
    }

    public void run() {
        try {
            System.out.println(queue.take());
            System.out.println(queue.take());
            System.out.println(queue.take());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}