youyichannel

志于道,据于德,依于仁,游于艺!

0%

阻塞队列05

SynchronousQueue

SynchronousQueue是一个不存储元素的阻塞队列。每一个put操作必须等待一个take操作,否则他不能继续添加元素。

它支持公平的访问队列。默认情况下线程采用非公平性策略访问队列。使用以下构造方法可以创建公平性访问的SynchronousQueue,如果设置为true,则等待的线程会采用先进先出的顺序访问队列。

public SynchronousQueue(boolean fair) {
transferer = fair ? new TransferQueue<E>() : new TransferStack<E>();
}

几点说明:

1)SynchronousQueue 时存储数据的队列,阻塞队列。使用场景:适合短期的小并发场景,且数据处理相当快速。

首先该类没有缓冲容量,可以避免在服务器宕机的情况下,从queue的角度来说,没有数据丢失这一说。SynchronousQueue 可以看成是一个传球手,负责把生产者线程处理的数据直接传递 给消费者线程。队列本身并不存储任何元素,非常适合传递性场景。SynchronousQueue 的吞吐量高于 LinkedBlockingQueue 和 ArrayBlockingQueue。

2)CachedThreadPool中使用的就是SynchronousQueue。CachedThreadPool的使用场景就是处理快速的短期的小并发场景。CachedThreadPool中是没有核心线程数的,完全依赖最大线程数,直接依赖操作系统创建线程,如果是短期的小并发,在线程达到keepalive时间以后,可以自行销毁。

public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),
threadFactory);
}

LinkedTransferQueue

LinkedTransferQueue 是一个由链表结构组成的无界阻塞 TransferQueue 队列。相对于 其他阻塞队列,LinkedTransferQueue 多了 tryTransfer 和 transfer 方法。

  1. transfer方法

    如果当前有消费者正在等待接收元素(消费者使用take()方法或带时间限制的poll()方法时),transfer 方法可以把生产者传入的元素立刻 transfer给消费者(跟SynchronousQueue类似)。如果没有消费者在等待接收元素,transfer 方法会将元素存放在队列的 tail 节点,并等到该元素被消费者消费了才返回。

  2. tryTransfer方法

    tryTransfer 方法是用来试探生产者传入的元素是否能直接传给消费者。如果没有消费者等待接收元素,则返回 false。和 transfer方法的区别是 tryTransfer 方法无论消费者是否接收,方法立即返回,而 transfer 方法是必须等到消费者消费了才返回。

    对于带有时间限制的 tryTransfer(E e,long timeout,TimeUnit unit)方法,试图把 生产者传入的元素直接传给消费者,但是如果没有消费者消费该元素则等待指定的时间 再返回,如果超时还没消费元素,则返回 false,如果在超时时间内消费了元素,则返回 true。

LinkedBlockingDeque

LinkedBlockingDeque 是一个由链表结构组成的双向阻塞队列。所谓双向队列指的是可以从队列的两端插入和移出元素。双向队列因为多了一个操作队列的入口,在多线程同时入队时,也就减少了一半的竞争。

在初始化 LinkedBlockingDeque 时可以设置容量防止其过度膨胀。另外,双向阻塞队列可以运用在“工作窃取”模式中。

应用场景:没有严格的顺序控制的场景使用。比如将10个任务添加到双端队列,起两个线程进行任务处理(处理顺序无所谓,只要都处理完汇总即可),选择双端队列会减少竞争。