ArrayBlockingQueue的基本使用:
1、ArrayBlockingQueue是一个用数组实现的有界阻塞队列,内部按照先进先出的原则排序,take和put方法分别是添加和删除元素的阻塞方法。
2、其内部是通过一个可重入锁ReenterLock和Conditon条件队列实现的,所有访问队列的时候存在公平和非公平的区别(默认非公平锁)。
LinkedBlockingQueue的基本使用:
1、LinkedBlockingQueue是一个用链表实现的有界阻塞队列,内部按照先进先出的原则排序。
2、队列的大小默认值为Integer.MAX_VALUE, 建议初始化一个定长的队列,如果使用默认的大小,当消费者的消费能力小于生产者的生产能力时,可能会导致队列的数据量越来越庞大,造成内存不足。
3、其吞吐量要高于ArrayBlockingQueue,原因是LinkedBlockingQueue的新增和删除元素使用的是两把不同的可重入锁ReenterLock,可以并发运行。
ArrayBlockingQueue和LinkedBlockingQueue的异同点:
1、队列的初始化,ArrayBlockingQueue必须要指定大小,LinkedBlockingQueue可不指定大小,默认为Integer.MAX_VALUE,但是建议要给定大小,防止内存溢出的问题。
2、数据存储的容器不同,ArrayBlockingQueue采用数组来作为存储数据的容器,而LinkedBlockingQueue采用的是一Node节点作为连接对象的链表。
3、由于ArrayBlockingQueue采用的是数组的存储容器,因此在插入和删除元素时不会产生或销毁额外的对象实例,而LinkedBlockingQueue则会生成一个额外的Node对象。这可能在长时间内需要高效并发的处理大批量数据时的性能会有影响,比如GC。
4、两者的实现队列的添加和删除元素的锁机制不一样,ArrayBlockingQueue实现的队列中的锁是没有分离的,就是说其添加和删除用的同一把可重入锁。而LinkedBlockingQueue实现的队列中的添加元素和删除元素的锁是分离的,添加用putLock,移除则用takeLock, 这样能大大提高队列的吞吐量,也意味着在高并发的情况下生产者和消费者可以并行的操作队列,以此来提高整个队列的并发性能。
分享一个实际工作中用到阻塞队列遇到的问题:
LinkedBlockingQueue与CountDownLatch放在一起使用,定义了一个定长的LinkedBlockingQueue,先往队列里放数据,等到到达队列指定大小时,队列进入阻塞,然而因为配合了CountDownLatch使用,队列的消费被CountDownLatch的await()方法挡住了,导致互相在等待,最后抛出了超时异常。
所以这里要非常的小心,有界的阻塞队列,不能把消费端阻断了。