多线程之间交互线程之BlockingQueue

来源:互联网 发布:spps统计软件 编辑:程序博客网 时间:2024/05/17 03:57

线程阀是一种线程与线程之间相互制约和交互的机制。

1、阻塞队列BlockingQueue是一个支持两个附加操作的队列,这两个附加操作是:队列为空时,获取元素的线程会等待队列变为非空;当队列满时,存储元素的线程会等待队列可用。阻塞队列常用于生产者和消费者的场景,生产者是往队列里添加元素的线程,消费者是从队列里拿取元素的线程。阻塞队列作为生产者存放元素的容器,而消费者也只能从容器里拿取元素。(想要了解BlockingQueue方法的话请自行查阅API

2、数组阻塞队列ArrayBlockingQueueFIFO)是一个由数组支持的有界的阻塞队列。这是一个典型的“有界缓存区”,固定大小的数组在其中保存生产者插入的元素和使用者提取的元素。一旦创建了这样的缓存区,就不能再增加其容量。空时不可读,满时不可写。

3、链表阻塞队列LinkedBlockingQueueFIFO)是基于链表的阻塞队列。跟ArrayBlockingQueue差不多,不同的是:LinkedBlockingQueue对于生产者端和消费者端分别采用了独立的锁来控制数据同步,这也意味着在高并发的情况下生产者和消费者能够并行地操作队列中的数据,以此来提高整个队列的并发性能,同时若构造一个LinkedBlockingQueue对象时,没有指定LinkedBlockingQueue的容量大小,那么LinkedBlockingQueue会默认一个Integer.MAX_VALUE容量,也就是说,当生产者的速度一旦大于消费者的速度,也许还没等到队列满阻塞的产生,系统内存就有可能被消耗殆尽了。

4、优先阻塞队列PriorityBlockingQueue是一个支持优先级排序的无界阻塞队列(优先级的判定通过传入的Compator对象来决定),但需要注意的是PriorityBlockingQueue并不会阻塞数据生产者,也就是说该容器不会有满的状态,只会在空时阻塞消费者,因此,与LinkedBlockingQueue一样,生产者生产数据的速度不能快于消费者消费数据的速度,不然时间一长,会耗尽所有的可用堆内存空间。实现PriorityBlockingQueue时,内部控制线程同步的锁采用的是公平锁。

5、延时队列DelayQueue是一个支持延时获取元素的使用优先级队列的实现的无界阻塞队列。队列里的元素必须实现Delayed接口和Comparable接口,该队列适用于:①缓存系统的设计。可以DelayQueue保存缓存元素的有效期,使用一个线程循环查询DelayQueue,一旦能从DelayQueue中获取元素时,表示缓存的有效期到了。②定时任务调度。使用DelayQueue保存当天将会执行的任务和执行时间。一旦从DelayQueue中获取任务就开始执行,比如TImerQueue就是使用DelayQueue实现的。

6、同步队列SynchronousQueue是一个不存储元素的队列。它适用于一个线程使用的数据传递到另一个线程,SynchronousQueue的吞吐量高于LinkedBlockingQueue和ArrayBlockingQueue。SynchronousQueue有两种模式:公平模式和非公平模式的区别:公平模式下SynchronousQueue采用公平锁,并配合一个FIFO队列来阻塞多余的生产者和消费者;非公平模式下(SynchronousQueue默认的模式),SynchronousQueue采用非公平锁,同时配合一个LIFO队列来管理多余的生产者和消费者,需要注意的是,当生产这和消费者的处理速度有差距,就很容易产生某些生产者或者是消费这的数据永远都得不到处理(饥渴状态)。

7、链表双向阻塞队列LinkedBlockingDeque是一个由链表结构组成的双向阻塞队列,由于多了一个操作队列的入口,在多线程同时入队时,也就减少了一半的竞争。初始化LinkedBlockingDeque时可以设置容量防止过度膨胀。另外,双向阻塞队列可以运用在“工作窃取”模式中,与LinkedBlockingQueue有点类似。

8、链表传输队列LinkedTransferQueue是一个由链表结构组成的无界传输阻塞队列。LinkedTransferQueue是TransferQueue的实现类,TransferQueue继承了BlockingQueue的接口,同时也增加了若干的新方法。transfer大致的理解是采用双重数据结构(dual data structures)。之所以叫双重,其原因是方法都是通过两个步骤完成:保留与完成。例如:消费者线程从一个队列中取元素,发现队列为空,它就生成一个空元素(即数据字段为空)然后消费者线程在这个字段上继续等待,这叫做保留。然后直到一个生产者线程想往队列放入一个元素,此时它发现最前面的元素为空空元素,就直接把自己的数据填充到这个元素中,即完成了元素的传送。需要注意的是:①无论是transfer还是tryTransfer方法,在>=1个消费者线程等待获取元素时(此时队列为空),都会立即转交,这属于线程之间的元素交换(此时元素并没有进入队列)。②在队列中已有数据的情况下,transfer将需要等待前面数据被消费掉,直到传递的元素被消费者线程取走为止。③使用transfer方法,工作者线程可能会被阻塞到生产的元素被消费掉位置。消费者线程等待为0的情况下,各自(transfer、tryTransfer)的处理元素入队与否情况有所不同。④size方法,需要迭代,可能不太准确,不建议调用。

0 0