最近看《分布式JAVA应用 基础与实践》 里面有一段话
林昊 写道
ArrayBlockingQueue为一个固定大小数组、ReentrantLock以及Condition实现的可阻塞的先进先出的Queue。
除ArrayBlockingQueue之外,BlockingQueue的实现还有LinkedBlockingQueue,LinkedBlockingQueue实现的不同为采用对象的next构成链表的方式存储对象。由于读只操作对头,而写只操作队尾,这里巧妙地采用了两把锁,对于put和offer采用一把锁,对于take和poll则采用另外一把锁,避免了读写时互相竞争锁的情况,因此LinkedBlockingQueue在高并发读写操作都多的情况下,性能会较ArrayBlockingQueue好很多,在遍历以及删除元素则要两把锁都锁住。
除ArrayBlockingQueue之外,BlockingQueue的实现还有LinkedBlockingQueue,LinkedBlockingQueue实现的不同为采用对象的next构成链表的方式存储对象。由于读只操作对头,而写只操作队尾,这里巧妙地采用了两把锁,对于put和offer采用一把锁,对于take和poll则采用另外一把锁,避免了读写时互相竞争锁的情况,因此LinkedBlockingQueue在高并发读写操作都多的情况下,性能会较ArrayBlockingQueue好很多,在遍历以及删除元素则要两把锁都锁住。
乍一看,ArrayBlockingQueue怎么都不如LinkedBlockingQueue性能强大,那ArrayBlockingQueue存在的意义是什么呢?带着这个疑问,自己亲身写了个程序,4个生产者总共生产4* 102,4000*10个产品,4个消费者去消费,队列的最大大小是102,4000,队列分别采用ArrayBQ和LinkedBQ,对比2者消耗时间。(读者可以直接运行该程序得出对比结果)。
import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ArrayBlockingQueue; public class ArrayBlockingQueueVsLinkedBlockingQueue { //队列最大容量 public static final int Q_SIZE = 1024000; //生产者/消费者线程数 public static final int THREAD_NUM = 4; //产品 class Product{ String name; Product(String name){ this.name = name; } } public void test(final BlockingQueue<Product> q) throws InterruptedException{ //生产者线程 class Producer implements Runnable{ @Override public void run() { for(int i=0;i<Q_SIZE*10;i++){ try { q.put(new Product("Lee")); } catch (InterruptedException e) { e.printStackTrace(); } } } }; //消费者线程 class Consumer implements Runnable{ @Override public void run(){ for(int i=0;i<Q_SIZE*10;i++){ try { q.take(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }; //创建生产者 Thread[] arrProducerThread = new Thread[THREAD_NUM]; for(int i=0;i<THREAD_NUM;i++){ arrProducerThread[i] = new Thread(new Producer()); } //创建消费者 Thread[] arrConsumerThread = new Thread[THREAD_NUM]; for(int i=0;i<THREAD_NUM;i++){ arrConsumerThread[i] = new Thread(new Consumer()); } //go! long t1 = System.currentTimeMillis(); for(int i=0;i<THREAD_NUM;i++){ arrProducerThread[i].start(); arrConsumerThread[i].start(); } for(int i=0;i<THREAD_NUM;i++){ arrProducerThread[i].join(); arrConsumerThread[i].join(); } long t2 = System.currentTimeMillis(); System.out.println(q.getClass().getSimpleName() + " cost : " + (t2-t1)); } public static void main(String[] args) throws InterruptedException{ final BlockingQueue<Product> q1 = new LinkedBlockingQueue<Product>(Q_SIZE); final BlockingQueue<Product> q2 = new ArrayBlockingQueue<Product>(Q_SIZE); new ArrayBlockingQueueVsLinkedBlockingQueue().test(q1); new ArrayBlockingQueueVsLinkedBlockingQueue().test(q2); } }
结果令人我意外,ArrayBQ耗时只有LinkedBQ的一半!而且运行的时候ArrayBQ没占满CPU,LinkedBQ却一直占满!
(我的机器 JDK1.6 win7_64 -Xms1024M -Xmx1024M)
(群友的机器)
我这就不懂了,锁竞争更小的LinkedBQ输给了ArrayBQ。。。难道是线程不够多?
于是我把参数改成以下
//队列最大容量 public static final int Q_SIZE = 10240; //生产者/消费者线程数 public static final int THREAD_NUM = 1280;
结果还是ArrayBQ更快。。。
各位技术的朋友,这究竟解释?如果您知道为什么,请务必留言告知鄙人!
我现在唯一的想到的是,LinkedQueue需要建立Node,而且增删时引用的操作比ArrayBQ复杂。ArrayBQ的内部的数组在增删时并不会产生复制的操作,而是当作一个环,增删只会改变putIndex和takeIndex,操作非常简单。
相关推荐
`ArrayBlockingQueue` 是一种高性能的并发队列实现,适合高吞吐量的场景,但相比于其他无界队列(如 `LinkedBlockingQueue`),它的延迟可能会更高。这是因为有界队列需要处理满和空的情况,可能需要线程等待。 7....
"并发容器之ArrayBlockingQueue和LinkedBlockingQueue实现原理详解" ArrayBlockingQueue和LinkedBlockingQueue是Java并发容器中两个常用的阻塞队列实现,分别基于数组和链表存储元素。它们都继承自AbstractQueue类...
—BlockingQueue和ArrayBlockingQueue.pdf” 【描述】:此文档是关于Java并发编程的学习资料,以漫画形式讲解,聚焦于Java并发编程中的核心概念——BlockingQueue接口及其具体实现ArrayBlockingQueue。 【标签】:...
3. 数组阻塞队列 ArrayBlockingQueue 4. 延迟队列 DelayQueue 5. 链阻塞队列 LinkedBlockingQueue 6. 具有优先级的阻塞队列 PriorityBlockingQueue 7. 同步队列 SynchronousQueue 8. 阻塞双端队列 BlockingDeque 9. ...
数组阻塞队列 ArrayBlockingQueue 4. 延迟队列 DelayQueue 5. 链阻塞队列 LinkedBlockingQueue 6. 具有优先级的阻塞队列 PriorityBlockingQueue 7. 同步队列 SynchronousQueue 8. 阻塞双端队列 BlockingDeque 9. 链...
3. 数组阻塞队列 ArrayBlockingQueue 4. 延迟队列 DelayQueue 5. 链阻塞队列 LinkedBlockingQueue 6. 具有优先级的阻塞队列 PriorityBlockingQueue 7. 同步队列 Synchronou sQueue 8. 阻塞双端队列 BlockingDeque 9...
相比于基于数组的`ArrayBlockingQueue`,`LinkedBlockingQueue`在大多数情况下具有更好的性能,因为插入和删除操作不需要数组的重新分配。 五、公平与非公平策略 `LinkedBlockingQueue`有两种策略:公平(FIFO)和...
Java中的`LinkedBlockingQueue`和`ArrayBlockingQueue`都是`java.util.concurrent`包下的线程安全队列,它们都实现了`BlockingQueue`接口,提供了一种高效、线程安全的数据同步方式。这两种队列在很多方面都有相似之...
3. 数组阻塞队列 ArrayBlockingQueue 4. 延迟队列 DelayQueue 5. 链阻塞队列 LinkedBlockingQueue 6. 具有优先级的阻塞队列 PriorityBlockingQueue 7. 同步队列 SynchronousQueue 8. 阻塞双端队列 BlockingDeque 9. ...
3. 数组阻塞队列 ArrayBlockingQueue 4. 延迟队列 DelayQueue 5. 链阻塞队列 LinkedBlockingQueue 6. 具有优先级的阻塞队列 PriorityBlockingQueue 7. 同步队列 SynchronousQueue 8. 阻塞双端队列 BlockingDeque 9. ...
1. 目录 1. 2. 目录 .........................................................................................................................................................1 JVM .........................
1. 目录 1. 2. 目录 .........................................................................................................................................................1 JVM ........................
ArrayBlockingQueue是Java并发编程中一个重要的数据结构,它是JDK内置的并发队列,源自java.util.concurrent包下的`java.util.concurrent.ArrayBlockingQueue`类。这个队列基于数组实现,支持阻塞插入和移除操作,是...
LinkedBlockingQueue相比ArrayBlockingQueue,LinkedBlockingQueue的优点是可以自动扩容,不需要在创建时指定队列的大小。同时,LinkedBlockingQueue也可以避免ArrayBlockingQueue的缺点,即数组长度小了会导致队列...
与数组结构的`ArrayBlockingQueue`不同,`LinkedBlockingQueue`使用单向链表实现,这使得插入和删除操作的效率相对较高,因为它们只需要修改相邻节点的引用。链表的头节点`head`不包含有效数据,而尾节点`last`保存...
Java并发之ArrayBlockingQueue详细介绍 ArrayBlockingQueue是Java并发编程中常用的线程安全队列,经常被用作任务队列在线程池中。它是基于数组实现的循环队列,具有线程安全的实现。 ArrayBlockingQueue的实现 ...
与ArrayBlockingQueue不同,LinkedBlockingQueue的容量可以是Integer.MAX_VALUE(即无界队列),也可以在构造时指定。由于链表结构,插入和删除操作的时间复杂度为O(1),但相比于ArrayBlockingQueue,它在空间效率上...