`

Java并发包:阻塞队列(BlockingQueue)

 
阅读更多
http://blog.csdn.net/zxc123e/article/details/51837866

文章译自:http://tutorials.jenkov.com/java-util-concurrent/index.html
抽空翻译了一下这个教程的文章,后面会陆续放出,如有不妥,请批评指正。
转自请注明出处。

BlockingQueue

在Java.util.concurrent包中的 BlockingQueue接口类是一种线程安全的队列。这篇文章我们将展示如何使用BlockingQueue。

这篇文章不讨论BlockQueue的实现。如果你对此感兴趣,有一片理论的文章 Blocking Queues

BlockingQueue的使用说明

BlockingQueue一般用于这样的场景:一个线程生产对象,另一个线程来消耗对象,下面的插图说明了这个规则:
这里写图片描述
生产线程会持续生产新的对象并把他们插入到队列中,直到队列所能包含对象的最大上限。
如果阻塞队列到达了上限,这时如果尝试插入新的的对象,生产线程将会被阻塞。并且阻塞会一直保持直到消费线程从队列中取出一个对象。

同样,消费线程会持续从阻塞队列中取出对象并处理他们。如果消费线程试图从一个空的队列中取出对象,消费线程将被阻塞住,直到生产线程向队列中加入了一个对象。

BlockingQueue方法。

对于在队列中插入、删除和检查元素操作BlockingQueue有4类不同行为的方法。

operation Throws Exception Special Value Blocks Times Out
Insert add(o) offer(o) put(o) offer(o, timeout, timeunit)
Remove remove(o) poll() take() poll(timeout, timeunit)
Examine element() peek()
四种不同行为的含义如下:

1.抛异常
如果尝试操作是不可能的,一个异常将会抛出。
2.特殊值
如果尝试操作是不可能的,一个特殊值将返回(通常是true/false)
3.阻塞
如果尝试操作是不可能的,方法将会阻塞住,直到可以执行。
4.超时
如果尝试操作是不可能的,方法将会阻塞住,直到可以执行,但是阻塞不会超过给定的时间。并且返回一个特定的值来表示操作是否成功(一般是true/false)。
不能向BlockingQueue中插入null,否则会抛出NullPointerException异常。

访问BlockingQueue中的任意元素也是可能的,不仅仅是在队列前端和末端的元素。例如,你已经排队了一个待处理的对象(有了一个队列),然而你的应用程序需要取消该对象。这时你可以调用remove(o)方法从队列中移除该对象。然而,这种做法不是高效的,因此应该尽量避免使用,除非你真的需要这么做。

BlockingQueue的实现

由于BlockingQueue是一个接口,你需要使用它的具体实现类,java.util.concurrent包中了下面的对于BlockingQueue的具体实现:

ArrayBlockingQueue
DelayQueue
LinkedBlockingQueue
PriorityBlockingQueue
BlockingQueue示例

下面是BlockingQueue的使用示例。这个例子使用了BlockingQueued的一个具体实现类ArrayBlockingQueue。

首先,BlockingQueueExample类开启了Producer和Consumer两个不同的线程,Producer线程向共享BlockingQueue中插入字符串,Consumer线程从中取出它们。

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);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
下面是Producer类,注意每次调用put()方法线程将睡1秒。这将引起Consumer阻塞,一直等待对象加入到队列中。

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();
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
下面是Consumer类。它从队列中取出对象,并打印出来结果。

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();
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
ArrayBlockingQueue

ArrayBlockingQueue是一个有边界,阻塞队列,元素存储在内部的数组当中。有边界意味着它不能存储无限的元素。这里有一个可同时存储元素的上边界。你可以在实例化的时候设置这个上边界,但之后这个值不能被改变。

ArrayBlockingQueue内部以FIFO(先进先出)的顺序存储元素。队列头部元素将在队列中保持最长的时间。队列尾部的元素将在队列中保持最短的时间。

这里展示如何实例化和使用一个ArrayBlockingQueue:

BlockingQueue queue = new ArrayBlockingQueue(1024);

queue.put("1");

Object object = queue.take();
1
2
3
4
5
1
2
3
4
5
下面是一个BlockingQueue使用泛型的例子。

BlockingQueue<String> queue = new ArrayBlockingQueue<String>(1024);

queue.put("1");

String string = queue.take();
1
2
3
4
5
1
2
3
4
5
DelayQueue

DelayQueue内部阻塞元素直到某个延迟到期。其中元素必须实现java.concurrent.Delayed接口。下面是Delayed接口:

public interface Delayed extends Comparable<Delayed< {

public long getDelay(TimeUnit timeUnit);

}
1
2
3
4
5
1
2
3
4
5
getDelay()方法返回的值代表元素被释放前应该延迟的时间。如果返回的是0或者负数,延迟被认为是到期的或者说是期满的,接下来在DelayQueue上调用take()等方法后,元素将会释放。

传给getDelay()方法的TimeUnit实例是Enum类型,它判断那种延迟时间单位被返回。TimeUnit的可能的取值:

DAYS
HOURS
MINUTES
SECONDS
MILLISECONDS
MICROSECONDS
Delayed接口也继承了java.lang.Comparable接口,正如你所看到的,这也意味着Delayed的对象可以相互比较。这可能被用在DelayQueue内部给队列中元素排序,这样元素将在期满时将按照顺序被释放。

下面是一个如何使用DelayQueue的例子:

public class DelayQueueExample {

    public static void main(String[] args) {
        DelayQueue queue = new DelayQueue();

        Delayed element1 = new DelayedElement();

        queue.put(element1);

        Delayed element2 = queue.take();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
1
2
3
4
5
6
7
8
9
10
11
12
DelayedElement是我自己创建的对Delayed接口的一个具体实现,它不是java.util.concurrent包中的一部分。你在使用DelayQueue类时必须先创建一个你自己的Delayed接口的具体实现。

LinkedBlockingQueue

LinkedBlockingQueue内部使用一个链表结构保存元素。这种链表结构能够有个理想的上边界,如果没有指定上边界,那么使用Integer.MAX_VALUE作为上边界。

LinkedBlockingQueue内部存储元素遵循FIFO的规则。队列头部元素将在队列中保持最长的时间。队列尾部的元素将在队列中保持最短的时间。

下面是如何实例化和使用LinkedBlockingQueue:

BlockingQueue<String> unbounded = new LinkedBlockingQueue<String>();
BlockingQueue<String> bounded   = new LinkedBlockingQueue<String>(1024);

bounded.put("Value");

String value = bounded.take();
1
2
3
4
5
6
1
2
3
4
5
6
PriorityBlockingQueue

PriorityBlockingQueue是一种无边界的并发队列。它遵循java.util.PriorityQueue类同样的规则。这种队列中不能插入null值。

优先队列是不同于先进先出队列的另一种队列。每次从队列中取出的是具有最高优先权的元素。

PriorityQueue是从JDK1.5开始提供的新的数据结构接口。
如果不提供Comparator的话,优先队列中元素默认按自然顺序排列,也就是数字默认是小的在队列头,字符串则按字典序排列。
所有插入到PriorityBlockingQueue 中的元素必须实现java.lang.Comparable接口。因此元素会根据你的Comparable实现来排序。

注意:PriorityBlockingQueue 中不能强制指定元素具有相同的优先级(compare() == 0).
同时也要注意,假使得到PriorityBlockingQueue 的迭代器(Iterator),迭代器不能保证按元素优先级迭代。

下面是一个如何使用PriorityBlockingQueue的例子:

BlockingQueue queue   = new PriorityBlockingQueue();

    //String implements java.lang.Comparable
    queue.put("Value");

    String value = queue.take();
1
2
3
4
5
6
1
2
3
4
5
6
SynchronousQueue

SynchronousQueue 是内部仅包含单一元素的队列。一个向队列中插入元素的线程会被阻塞直到另一个线程从队列中取走元素。同样的,如果一个线程试图取出元素而当前没有元素,这个线程会被阻塞直到另一个线程向队列中插入了元素。
称这个类为一个队列有点夸张。它更像是一个会合点。
分享到:
评论

相关推荐

    java并发包资源

    2. 阻塞队列 BlockingQueue 3. 数组阻塞队列 ArrayBlockingQueue 4. 延迟队列 DelayQueue 5. 链阻塞队列 LinkedBlockingQueue 6. 具有优先级的阻塞队列 PriorityBlockingQueue 7. 同步队列 SynchronousQueue 8. 阻塞...

    java线程聊天室(阻塞队列实现)

    而阻塞队列(Blocking Queue)是Java并发包(java.util.concurrent)中的一种高效数据结构,常用于线程间的协作,它能够简化同步问题并提高系统性能。 阻塞队列是一种特殊的队列,当队列为空时,取出元素的操作将会...

    Java并发编程--BlockingQueue.docx

    BlockingQueue 是 Java 并发包(java.util.concurrent)中的一个接口,它扩展了 Queue 接口,并引入了线程安全的特性,特别适合于多线程环境下的数据共享。 BlockingQueue 的核心设计是其在并发环境下提供了高效的...

    生产者/消费者模式 阻塞队列 LinkedBlockingQueue

    在Java中,阻塞队列(BlockingQueue)是一个很好的实现生产者/消费者模式的工具,而LinkedBlockingQueue则是Java并发包(java.util.concurrent)中提供的一个具体实现。 LinkedBlockingQueue是一个基于链表结构的...

    并发-线程池和阻塞队列

    阻塞队列(BlockingQueue)是Java并发包(java.util.concurrent)中的一个重要数据结构,它实现了队列的特性,同时具备线程安全的特性。当队列满时,添加元素的线程会被阻塞,直到队列有空位;当队列为空时,取出...

    Java并发编程(21)并发新特性-阻塞队列和阻塞栈(含代

    这些数据结构源自Java的并发包`java.util.concurrent`,是实现并发设计模式如生产者消费者模型的基础。 **阻塞队列(BlockingQueue)** 阻塞队列是一种特殊的队列,当队列为空时,从队列中获取元素的操作将会被...

    spring-blockingqueue:用Spring Boot阻止队列

    BlockingQueue是Java并发包`java.util.concurrent`中的一个接口,它提供了在队列满时阻塞插入操作和队列空时阻塞删除操作的能力。这种设计模式被称为生产者-消费者模型,它有效地解决了线程间的同步问题,避免了不必...

    基于java中BlockingQueue的使用介绍

    Java并发包 `java.util.concurrent` 中提供了一些实现 BlockingQueue 的类,如 `ArrayBlockingQueue`、`LinkedBlockingQueue` 和 `PriorityBlockingQueue` 等。这些类各有特点,适用于不同的场景: - `...

    java 提供消息队列的使用

    阻塞队列是Java并发包`java.util.concurrent`中的一个数据结构,它结合了队列和锁的概念,常用于构建高效的消息传递机制。在生产者-消费者问题中,阻塞队列能自动同步生产者和消费者的动作,当队列满时,生产者会被...

    day19_阻塞队列、线程池、File类、递归.pdf

    阻塞队列(BlockingQueue)是Java并发包(java.util.concurrent)中的一种数据结构,它在队列为空或满时,能够自动阻塞生产者或消费者的线程,直到条件满足为止。这种机制保证了线程间的同步和协作,避免了不必要的...

    并发容器——BlockingQueue相关类

    在Java编程中,`BlockingQueue`是一个非常重要的并发容器,它是Java并发包`java.util.concurrent`中的核心组件。`BlockingQueue`实现了一种线程安全的数据结构,它能够有效地协调生产者和消费者的动作,实现高效的...

    2011.08.30(2)——— java BlockingQueue ExecutorService

    BlockingQueue是Java并发包`java.util.concurrent`中的一个接口,它是一种特殊的队列,当队列为空时,获取元素的操作将会被阻塞,直到有新的元素添加;反之,当队列满时,插入元素的操作也会被阻塞,直到队列中有...

    idea+java多线程模拟队列实现排队叫号.zip

    这个项目可能采用了`BlockingQueue`接口,它是Java并发包中的一种高效队列实现,提供线程安全的插入和取出操作,且具有阻塞特性:当队列为空时,取操作会阻塞,直到有新的元素加入;当队列满时,插入操作也会阻塞,...

    并发队列ConcurrentLinkedQueue和阻塞队列LinkedBlockingQueue用法

    `LinkedBlockingQueue` 同样是 `java.util.concurrent` 包下的一个线程安全的阻塞队列实现,它继承自 `AbstractQueue` 并实现了 `BlockingQueue` 接口。`LinkedBlockingQueue` 的特点是可以在队列满时阻塞生产者线程...

    JavaConcurrency:这是一个用于Java并发包的学习程序

    Java并发包(java.util.concurrent)提供了一系列的类和接口,旨在简化多线程环境下的编程,提高应用程序的性能和可伸缩性。 首先,我们要了解Java中的线程。线程是程序执行的最小单元,一个进程可以有多个线程同时...

    Java线程唤醒与阻塞常用方法共2页.pdf.zip

    - `ReentrantLock`: Java并发包中的`java.util.concurrent.locks.ReentrantLock`提供了更细粒度的锁控制,包括公平锁、非公平锁、可中断锁等待和定时锁等待。 - `Semaphore`: 信号量,用于限制同时访问特定资源的...

    多线程并发集合资料.zip

    - `BlockingQueue`:阻塞队列,如`ArrayBlockingQueue`和`LinkedBlockingQueue`,在队列满或空时,线程会被阻塞,实现生产者-消费者模式。 - `CopyOnWriteArrayList` 和 `CopyOnWriteArraySet`:在读多写少的场景...

    Java并发之BlockingQueue的使用

    BlockingQueue是Java并发包(java.util.concurrent)中的接口,提供了阻塞功能的队列。当队列满时,尝试插入元素的线程会被阻塞,直到队列中有空间;同样,当队列空时,尝试取出元素的线程也会被阻塞,直到队列中有...

Global site tag (gtag.js) - Google Analytics