在jdk中有许多的队列,队列的使用还是有一些难度的,因为涉及到了并发等概念,现在我们列举一下队列的特点:
- 并发情况下不会有线程安全问题
- 队列都有元素
- 都有添加(生产者端使用)、获取(消费者端使用)功能
- 基本上的使用场景都是在多线程、高并发的场景
在jdk中的队列有如下几种:
1、LinkedBlockingQueue
LinkedBlockingQueue是使用比较多的队列,在SingleThreadPool(单个线程的线程池)、FixedThreadPool(固定线程数的线程池)使用的都是LinkedBlockingQueue。
1、在LinkedBlockingQueue中有两个ReentrantLock,takeLock和putLock分别是在添加元素和取出元素的时候添加的锁。
2、LinkedBlockingQueue是无界队列。
2、ArrayBlockingQueue
ArrayBlockingQueue是有界队列,在阿里的开源框架RocketMq中就使用到了,其添加和获取都是用的同一个ReentrantLock。
3、SynchronousQueue
SynchronousQueue是只有一个元素的队列,
- 其添加和获取方法都用到了transfer方法
public boolean offer(E e) {
if (e == null) throw new NullPointerException();
return transferer.transfer(e, true, 0) != null;
}
public E take() throws InterruptedException {
E e = transferer.transfer(null, false, 0);
if (e != null)
return e;
Thread.interrupted();
throw new InterruptedException();
}
其是根据是否有元素来区分是添加元素还是获取元素。
- 其有两种元素添加获取方式,非公平获取和公平获取
非公平用的是TransferStack,是后进先出的方式
公平方式用的是TransferQueue,是先进先出方式 - 加锁是用的CAS的方式替换
使用场景:在CachedThreadPool线程池中,使用到了SynchronousQueue。
4、ConcurrentLinkedQueue
ConcurrentLinkedQueue数据结构进行了非常巧妙的设计,在添加是从tail节点,获取是从head节点,而且做到了方并发,因为不用锁,所以效率更高。
在netty的读取byteBuffer和获取Selector中都用了ConcurrentLinkedQueue。具体详细原理,可以网上搜索,在此不再赘述
5、LinkedTransferQueue
LinkedTransferQueue是jdk才出现的队列,是LinkedBlockingQueue、SynchronousQueue、ConcurrentLinkedQueue的超集,实现了他们三个的功能,其添加和获取都是用的xfer方法。