ArrayBlockingQueue 是一个有界队列,基于数组实现,在 ArrayBlockingQueue 内部,维护了一个定长数组,以便缓存队列中的数据对象,按照FIFO的方式排序;入队与出队的操作,使用同一个 ReentrantLock 来进行控制;
public class ArrayBlockingQueue<E> extends AbstractQueue<E>
implements BlockingQueue<E>, java.io.Serializable {
// ArrayBlockingQueue使用定长数组做为存储结构
final Object[] items;
/** Main lock guarding all access */
final ReentrantLock lock;
// 创建时传入数组容量(长度)
public ArrayBlockingQueue(int capacity) {
this(capacity, false);
}
}
// 使用ArrayBlockingQueue创建自定义线程池
ExecutorService executorService =
new ThreadPoolExecutor(1, 2, 1000, TimeUnit.MILLISECONDS,
new ArrayBlockingQueue<Runnable(10),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
LinkedBlockingQueue是一个无界队列,基于单向链表结构,可以选择进行设置容量。如果不设置容量的话,最大长度为 Integer.MAX_VALUE。入队与出队的操作,使用不同ReentrantLock来进行控制,所以LinkedBlockingQueue 吞吐量通常要高于 ArrayBlockingQuene。
public class LinkedBlockingQueue<E> extends AbstractQueue<E>
implements BlockingQueue<E>, java.io.Serializable {
// 单向链表Node节点
static class Node<E> {
E item;
Node<E> next;
Node(E x) { item = x; }
}
/** Lock held by take, poll, etc */
private final ReentrantLock takeLock = new ReentrantLock();
/** Lock held by put, offer, etc */
private final ReentrantLock putLock = new ReentrantLock();
// 按照Integer.MAX_VALUE设置容量
public LinkedBlockingQueue() {
this(Integer.MAX_VALUE);
}
}
FixedThreadPool、SingleThreadExecutor线程池使用LinkedBlockingQueue 队列;
由于LinkedBlockingQueue是无界队列,线程池的任务队列可以无限制的添加新的任务,在这种情况下maximumPoolSize 参数是无效的,当线程池中的数量达到核心线程数时,线程数也不会增加,后续的任务会直接加到等待队列中
当使用这种任务队列模式时,一定要注意你任务提交与处理之间的协调与控制,不然会出现队列中的任务由于无法及时处理导致一直增长,直到最后资源耗尽的问题。
DelayedWorkQueue是基于堆结构的延迟队列,基于数组实现,初始容量为16,leader线程用于获取堆顶元素(队列头部元素)。该队列根据指定的延迟时间从小到大排序,如果延迟时间相同,则根据插入到队列的先后排序。
static class DelayedWorkQueue extends AbstractQueue<Runnable>
implements BlockingQueue<Runnable> {
private static final int INITIAL_CAPACITY = 16;
private RunnableScheduledFuture<?>[] queue = new RunnableScheduledFuture<?>[INITIAL_CAPACITY];
private Thread leader = null;
}
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
//.....
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
PriorityBlockingQueue 是一个基于优先级的无界队列(优先级的判断通过构造函数传入的Compator或元素实现Comparable接口来决定)。
**注意:**PriorityBlockingQueue并不会阻塞数据生产者,而只会在没有可消费的数据时,阻塞数据的消费者。因此使用的时候要特别注意,生产者生产数据的速度绝对不能快于消费者消费数据的速度,否则时间一长,会最终耗尽所有的可用堆内存空间。
每个订单使用一个线程进行支付,支付时按照订单金额的优先级。
// 订单类
public class PayOrder implements Runnable, Comparable<PayOrder> {
private int orderNo; // 订单编号
private BigDecimal payment; // 支付金额
public PayOrder(int orderNo, BigDecimal payment) {
this.orderNo = orderNo;
this.payment = payment;
}
@Override
public int compareTo(PayOrder o) {
return this.payment.compareTo(o.payment);
}
@Override
public void run() {
System.out.printf("订单编号为%d,订单金额为:¥%.1f的订单已完成支付!【%s】\n",orderNo,payment,Thread.currentThread().getName());
}
public int getOrderNo() {
return orderNo;
}
public void setOrderNo(int orderNo) {
this.orderNo = orderNo;
}
public BigDecimal getPayment() {
return payment;
}
public void setPayment(BigDecimal payment) {
this.payment = payment;
}
}
// 创建10个线程模拟订单支付
public class Test01 {
public static void main(String[] args) {
ThreadPoolExecutor pool=new ThreadPoolExecutor(2, 20, 10, TimeUnit.SECONDS,
new PriorityBlockingQueue<Runnable>());
pool.execute(new PayOrder(1, new BigDecimal("1943")));
pool.execute(new PayOrder(2, new BigDecimal("2000")));
pool.execute(new PayOrder(3, new BigDecimal("4000")));
pool.execute(new PayOrder(4, new BigDecimal("4356")));
pool.execute(new PayOrder(5, new BigDecimal("6543")));
pool.execute(new PayOrder(6, new BigDecimal("7433")));
pool.execute(new PayOrder(7, new BigDecimal("234")));
pool.execute(new PayOrder(8, new BigDecimal("1567")));
pool.shutdown();
}
// 运行结果
订单编号为1,订单金额为:¥1943.0的订单已完成支付!【pool-1-thread-1】
订单编号为2,订单金额为:¥7894.0的订单已完成支付!【pool-1-thread-2】
订单编号为10,订单金额为:¥1100.0的订单已完成支付!【pool-1-thread-1】
订单编号为4,订单金额为:¥1353.0的订单已完成支付!【pool-1-thread-2】
订单编号为3,订单金额为:¥3253.0的订单已完成支付!【pool-1-thread-1】
订单编号为7,订单金额为:¥3574.0的订单已完成支付!【pool-1-thread-2】
订单编号为8,订单金额为:¥3673.0的订单已完成支付!【pool-1-thread-1】
订单编号为6,订单金额为:¥5430.0的订单已完成支付!【pool-1-thread-2】
订单编号为5,订单金额为:¥6344.0的订单已完成支付!【pool-1-thread-1】
订单编号为9,订单金额为:¥8653.0的订单已完成支付!【pool-1-thread-2】
可以看到除了前2个任务直接创建线程执行外,其他的任务都被放入了优先任务队列,按优先级进行了重新排列执行,且线程池的线程数一直为2个(corePoolSize核心线程数)。
通过运行的代码我们可以看出PriorityBlockingQueue它其实是一个特殊的无界队列,它其中无论添加了多少个任务,线程池创建的线程数也不会超过corePoolSize的数量,只不过其他队列一般是按照先进先出的规则处理任务,而PriorityBlockingQueue队列可以自定义规则根据任务的优先级顺序先后执行。
SynchronousQueue是一个同步队列,它是一个不存储元素的阻塞队列(内部没有保存元素的数据结构容器),每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于LinkedBlockingQueue。
CachedThreadPool线程池使用这个队列
public class Main {
public static void main(String[] args) {
// maximumPoolSize设置为2 ,拒绝策略为AbortPolic策略(直接抛出异常)
ThreadPoolExecutor pool = new ThreadPoolExecutor(1, 2, 10, TimeUnit.MILLISECONDS,
new SynchronousQueue<Runnable>(),
new ThreadPoolExecutor.AbortPolicy());
// 执行的线程任务大于maximumPoolSize,执行拒绝策略
for (int i = 1; i <= 3; i++) {
pool.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "被执行!");
}
});
}
// 关闭线程池
pool.shutdown();
}
}
说明: