阻塞队列和生产者-消费者模式
阻塞队列提供了可阻塞的put和take方法。如果队列满了put将阻塞到有空间可用,如果队列为空,take将阻塞到有元素可用。队列可以是有界和无界的,无界的队列put将不会阻塞。
阻塞队列支持生产者消费者模式,该模式将找出需要完成的工作,和执行工作分开。生产者-消费者模式能简化开发过程,因为消除了生产者和消费者之间的代码依赖性,此外,该模式还将生产数据的过程和使用数据的过程解耦开来。
在基于阻塞队列构建的生产者-消费者设计中个,当数据生成时,生产者把数据放入队列,当消费者处理数据时,将从队列中获取数据。生产者无需知道消费者的标识和数量,消费者也不需知道生产者是谁。BlockingQueue简化了生产者-消费者设计的实现过程,支持任意数量的生产者和消费者。
阻塞队列简化了消费者程序的编码,因为take操作会一直阻塞到可用数据。如果生产者生成工作的速率比消费者处理工作的速率快,那么元素会在队列中累计起来,最终耗尽内存。同样put方法的阻塞特性也极大地简化了生产者的编码。如果使用有界队列,当队列充满时,生产者将阻塞并且不能继续生产,消费者就有时间赶上来处理工作。
阻塞队列同样提供了offer方法,如果数据不能添加到队列中,那么将返回一个失败状态。这样可以用灵活的策略来处理符合过载的情况,如减轻负载,减少生产者数量,增加消费者数量等。
在构建高可用的程序时,有界队列是一种强大的资源管理工具:能抑制并防止生产过多的工作项,使应用程序在负荷过载的情况下变得更加健壮。
在类库中,BlockingQueue有多种实现,其中LinkedBlockingQueue和ArrayBlockingQueue是FIFO队列,二者分别和LinkedList和ArrayList类似,但比同步List有更好并发性能。PriorityBlockingQueue是一个按优先级排序的队列,可以按照某种排序而不是FIFO来处理数据,和其他的有序容器一样。还有一个BlockingQueue的实现是SynchronousQueue,实际上维护的不是真正的队列,它不会为队列中元素维护存储空间。它维护一组线程,这些线程在等待着把元素加入或移除队列。其中每个插入操作必须等待另一个线程的对应移除操作,反之亦然。同步队列没有任何内部容量,甚至连一个队列的容量都没有。不能在同步队列上进行 peek,因为仅在试图要移除元素时,该元素才存在;除非另一个线程试图移除某个元素,否则也不能(使用任何方法)插入元素;也不能迭代队列,因为其中没有元素可用于迭代。因为同步队列没有存储功能,因此put和take将一直阻塞,直到有另一个线程已准备号参与到交付过程中。仅当有足够多的消费者,并且总有一个消费者准备好获取交付的工作时,才适合使用同步队列。