ThreadPoolExecutor源码历险-工作队列
ThreadPoolExecutor中的工作队列是这样定义的:
private final BlockingQueue<Runnable> workQueue;
从上面的UML图中可以看到我们可以用的工作队列类型有5种。这里我们简单的说下每个队列的特性,至于它们的源码篇幅过大,以后会单独开一个专题。
BlockingQueue(Interface)
BlockingQueue就是阻塞队列,阻塞是指某些情况下对阻塞队列的访问可能会造成阻塞
当一个线程试图对一个已经满了的队列进行入队列操作时,它将会被阻塞,除非有另一个线程做了出队列操作;同样,当一个线程试图对一个空队列进行出队列操作时,它将会被阻塞,除非有另一个线程进行了入队列操作。
下面表格展示了BlockingQueue方法的特性
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() |
Throws Exception 如果操作不能马上进行,则抛出异常
SpecialValue:如果操作不能马上进行,将会返回一个特殊的值,一般是true或者false
Blocks:如果操作不能马上进行,操作会被阻塞
TimesOut:如果操作不能马上进行,操作会被阻塞指定的时间,如果指定时间没执行,则返回一个特殊值,一般是true或者false
Delayed(Interface)
一种混合风格的接口,用来标记那些应该在给定延迟时间之后执行的对象。此接口的实现类要实现 compareTo 方法和getDelay方法
TransferQueue(Interface)
这类队列生产者会一直阻塞直到所添加到队列的元素被某一个消费者所消费,当我们不想生产者过度生产消息时,TransferQueue可能非常有用
DelayQueue
DelayQueue是一个无界阻塞队列,可以用做延时处理,所谓延时处理就是说可以为队列中元素设定一个过期时间,其中的元素只有在时间到期时才能从中被提取。DelayQueue里面的元素必须实现Delayed接口。
LinkedTransferQueue
LinkedTransferQueue是一个由链表结构组成的无界阻塞TransferQueue队列。相对于其他阻塞队列,LinkedTransferQueue多了tryTransfer和transfer方法。
LinkedTransferQueue采用一种预占模式。意思就是消费者线程取元素时,如果队列不为空,则直接取走数据,若队列为空,那就生成一个节点(节点元素为null)入队,然后消费者线程被等待在这个节点上,后面生产者线程入队时发现有一个元素为null的节点,生产者线程就不入队了,直接就将元素填充到该节点,并唤醒该节点等待的线程,被唤醒的消费者线程取走元素,从调用的方法返回。
LinkedTransferQueue是ConcurrentLinkedQueue、SynchronousQueue、LinkedBlockingQueue的超集。而且LinkedTransferQueue更好用,因为它不仅仅综合了这几个类的功能,同时也提供了更高效的实现。
LinkedBlockingQueue
LinkedBlockingQueue是基于链表的阻塞队列
LinkedBlockingQueue通常被认为是“无界”的,在默认情况下LinkedBlockingQueue的链表长度为Integer.MAX_VALUE。构造函数支持设置capacity,在使用的时候防止OOM,最好手动设置一个。
ArrayBlockingQueue
有界的阻塞队列,大小一旦创建后就无法改变。如果要调用put方法将元素放入完整队列,那么将会阻塞。如果要从空队列中调用take方法取元素也将会被阻塞。
该队列还支持设置是否公平模式,详情后边说源码的时候见分晓。
SynchronousQueue
SynchronousQueue不存储元素,其中每个 put 必须等待一个 take,相反也是一样。
SynchronousQueue没有任何内部容量,甚至连一个队列的容量都没有。不能在同步队列上进行 peek,因为仅在试图要取得元素时,该元素才存在;
除非另一个线程试图移除某个元素,否则也不能(使用任何方法)添加元素;
也不能迭代队列,因为其中没有元素可用于迭代。队列的头是尝试添加到队列中的首个已排队线程元素; 如果没有已排队线程,则不添加元素并且头为 null。
PriorityBlockingQueue
无界有序的阻塞队列,排序规则和PriorityQueue一致,该队列不支持插入null元素,同时不支持插入没有实现Comparable接口的对象