Java BlockingQueue

Java BlockingQueue是一个线程安全的队列接口,用于多线程环境中的元素插入和获取。它提供了多种方法,如add(), offer(), put(), take()等,不同方法在无法立即执行操作时有不同的处理方式,例如阻塞、返回特殊值或超时。文章通过示例展示了BlockingQueue的使用,包括Producer和Consumer线程的交互。" 51462597,5033959,Java注解详解与应用,"['Java', '注解', '元注解', '反射', '编程']
摘要由CSDN通过智能技术生成

本文翻译自http://tutorials.jenkov.com/java-util-concurrent/blockingqueue.html,机翻加人工校正,仅供学习交流。

Java BlockingQueue接口

Java BlockingQueue接口表示一个线程安全的队列,可以将元素放入,也可以取出。换句话说,多个线程可以同时从Java Bloc中插入和获取元素,不会有任何并发性问题。
阻塞队列这个术语就来自于Java BlockingQueue 接口能够阻塞试图在队列插入或获取元素的线程。如果一个线程尝试获取一个元素,而队列中没有剩余的,线程将被阻塞,直到有一个元素可以获取。调用线程是否被阻塞取决于你在BlockingQueue上调用什么方法。稍后将更详细地解释不同的方法。
本文将不讨论如何自己在Java中实现一个BlockingQueue。如果你对此感兴趣,我在更理论化的Java并发教程中有一篇关于阻塞队列的文章。

BlockingQueue实现类

因为BlockingQueue是一个接口,所以您需要使用它的一个实现来使用它。concurrent包有以下BlockingQueue接口的实现:
ArrayBlockingQueue
DelayQueue
LinkedBlockingQueue
LinkedBlockingDeque
LinkedTransferQueue
PriorityBlockingQueue
SynchronousQueue
点击列表中的链接,阅读关于每个实现的更多信息。

BlockingQueue用法

BlockingQueue通常用于让一个线程产生对象,另一个线程使用它。下面的图表说明了这一原理:一个BlockingQueue中,一个线程放入其中,另一个线程从其中取出。
生产线程将继续产生新的对象,并将它们插入到BlockingQueue中,直到队列达到它所能包含内容的某个上限,换句话说,这是极限。当阻塞队列达到其上限,生产线程在试图插入新对象时被阻塞。它将一直处于阻塞状态,直到一个正在使用的线程将一个对象从队列中取出。
消费线程不断地从BlockingQueue中取出对象来处理它们,如果使用线程试图从空队列中取出一个对象,消费线程被阻塞,直到生产线程将对象放入队列。

BlockingQueue方法

Java BlockingQueue接口有4组不同的方法,用于插入、删除和检查队列中的元素。当请求的操作不能及时执行时,每一组方法的操作都不同。下面是一个方法表:
在这里插入图片描述
这4种不同的行为意味着:

  1. Throws Exception:如果尝试的操作不能立即执行,则抛出异常。
  2. Special Value: 如果尝试的操作不能立即执行,则返回一个特殊值(通常为true / false)。
  3. Blocks: 如果尝试的操作不能立即执行,方法调用将阻塞,直到它能够执行为止。
  4. Times Out: 如果尝试的操作不能立即执行,方法调用会阻塞,但是等待的时间不会超过给定的超时时间。返回一个特殊值,告知操作是否成功(通常为true / false)。
    不可能将null值插入到BlockingQueue中,如果您试图插入null, BlockingQueue将抛出一个NullPointerException。
    你可以访问BlockingQueue中的所有元素,而不仅仅是开始和结束的元素。假设您已经将一个对象排队等待处理,但是你的程序决定取消它。然后你可以调用remove(o)来移除队列中的特定对象。然而,这并不是很有效,所以除非必要,否则不应该使用这些Collection方法。

Java BlockingQueue例子

下面是一个Java BlockingQueue示例。这个例子使用了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);
    }
}

接下来是Producer类。注意它是如何在每次put()调用之间休眠一秒钟的。这将导致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();
        }
    }
}

这是Consumer类。它只是从队列中取出对象,并将它们打印到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();
        }
    }
}
add()

如果BlockingQueue内部还有多余的空间,add()方法将添加以方法参数形式传递的元素。如果BlockingQueue内部没有用于此新元素的空间,add()方法抛出一个IllegalStateException。

offer()

如果BlockingQueue内部还有多余的空间,offer()方法将添加以方法参数形式传递的元素。如果BlockingQueue内部没有用于此新元素的空间,offer()方法返回false。

offer(long millis, TimeUnit timeUnit)

offer()方法存在于一个以超时为参数的版本中。如果BlockingQueue内部有空间容纳它,或者空间变得可用,这个版本的offer()方法添加以方法参数形式传递的元素。如果BlockingQueue在超时时间内没有为这个新元素获得内部空间,这个版本的offer()方法返回false。

put()

如果BlockingQueue内部还有多余的空间, put()方法将添加元素到队列中。如果BlockingQueue没有空间容纳新元素,在BlockingQueue有新元素的内部空间之前,put()方法将阻塞调用put()方法的线程。

take()

take()方法将删除BlockingQueue中的第一个元素。如果BlockingQueue不包含任何元素,在一个元素被插入到BlockingQueue之前,take()方法将阻塞调用take()的线程。

poll()

poll()方法将删除BlockingQueue中的第一个元素。如果BlockingQueue不包含任何元素,那么poll()方法将返回null。

poll(long timeMillis, TimeUnit timeUnit)

BlockingQueue poll(long timeMillis, TimeUnit TimeUnit)方法将删除BlockingQueue中的第一个元素。如果BlockingQueue不包含任何元素,这个版本的poll()方法将等待给定的时间内的可用元素,作为参数传递给它。如果在给定的超时时间内没有元素可用,该方法将返回null。

remove(Object o)

如果元素存在于BlockingQueue中,remove(Object o)方法将从BlockingQueue 中删除给定元素的单个实例。remove()方法将使用o.equals(元素)来决定如果对象o作为参数传递BlockingQueue匹配一个给定的元素。如果BlockingQueue包含多个匹配给定参数o的元素,这些元素中只有一个将从BlockingQueue中删除。如果元素被删除,remove()方法将返回true,否则返回false。

peek()

peek()方法将返回BlockingQueue的第一个元素,而不删除它。如果BlockingQueue不包含任何元素,那么peek()方法将返回null。

element()

element()方法将返回BlockingQueue的第一个元素,而不删除它。如果BlockingQueue不包含任何元素,那么element()方法将抛出NoSuchElementException。

contains(Object o)

如果BlockingQueue包含一个与作为参数传递给contains() 方法的对象匹配的对象,contains(Object o)方法将返回true。用Objects.equals(o,element)的值去校验参数对象o是否匹配BlockingQueue中的给定元素。如果找到与参数对象匹配的元素,该方法返回true。如果没有找到匹配的元素,则返回false。

drainTo(Collection dest)

drainTo(Collection dest)方法将BlockingQueue的所有元素排入给定的目标集合中。

drainTo(Collection dest, int maxElements)

drainTo(Collection dest, int maxElements)从BlockingQueue中抽取maxElements个数的元素到给定的目标集合中。

size()

size()方法返回存储在BlockingQueue中的元素数量。

remainingCapacity

remainingCapacity()方法返回BlockingQueue剩余的(未使用的)容量。剩余容量计算方法为满容量减去BlockingQueue中存储的元素数量。

下一节:ArrayBlockingQueue
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值