并发队列对比之二:LinkedBlockingQueue和ArrayBlockingQueue性能对比
回顾下,LinkedBlockingQueue和ArrayBlockingQueue在实现上不同点有:
1、ArrayBlockingQueue使用数组存储数据,LinkedBlockingQueue使用单向链表存储数据;
2、ArrayBlockingQueue使用一个可重入锁和这个锁生成的两个条件对象进行并发控制(classic two-condition algorithm),而LinkedBlockingQueue有2个锁,写锁和读锁,添加数据和删除数据是可以并行进行的,当然添加数据和删除数据的时候只能有1个线程各自执行。
一、写入性能对比:
package com.dxz.queue.linked; public class Bread { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Bread [name=" + name + "]"; } }
生产者和消费者及测试程序如下:
package com.dxz.queue.linked; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.CountDownLatch; public class ProducerArray implements Runnable{ //容器 private final ArrayBlockingQueue<Bread> queue; private final CountDownLatch cdl; public ProducerArray(ArrayBlockingQueue<Bread> queue, CountDownLatch cdl){ this.queue = queue; this.cdl = cdl; } @Override public void run() { for(int i=0;i<100000; i++){ produce(i); } cdl.countDown(); } public void produce(int i){ /** * put()方法是如果容器满了的话就会把当前线程挂起 * offer()方法是容器如果满的话就会返回false。 */ try { Bread bread = new Bread(); bread.setName(""+i); queue.put(bread); } catch (InterruptedException e) { e.printStackTrace(); } } } package com.dxz.queue.linked; import java.util.concurrent.CountDownLatch; import java.util.concurrent.LinkedBlockingQueue; public class ProducerLinked implements Runnable{ //容器 private final LinkedBlockingQueue<Bread> queue; private final CountDownLatch cdl; public ProducerLinked(LinkedBlockingQueue<Bread> queue, CountDownLatch cdl){ this.queue = queue; this.cdl = cdl; } @Override public void run() { for(int i=0;i<100000; i++){ produce(i); } cdl.countDown(); } public void produce(int i){ /** * put()方法是如果容器满了的话就会把当前线程挂起 * offer()方法是容器如果满的话就会返回false。 */ try { Bread bread = new Bread(); bread.setName(""+i); queue.put(bread); } catch (InterruptedException e) { e.printStackTrace(); } } } package com.dxz.queue.linked; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; public class ClientPut { public static void main(String[] args) throws InterruptedException { int capacity = 9000000; //testArray(capacity); //put in ArrayBlockingQueue size:=1000000,use time:=624 testLinked(capacity); //put in LinkedBlockingQueue size:=1000000,use time:=289 } private static void testArray(int capacity) throws InterruptedException { ArrayBlockingQueue<Bread> queue = new ArrayBlockingQueue<Bread>(capacity); CountDownLatch cdl = new CountDownLatch(10); ExecutorService es = Executors.newFixedThreadPool(10); long start = System.currentTimeMillis(); for(int i = 0; i < 10;i++) { es.submit(new ProducerArray(queue, cdl)); } cdl.await(); long end = System.currentTimeMillis(); es.shutdown(); System.out.println("put in ArrayBlockingQueue size:="+queue.size() +",use time:="+(end-start)); } private static void testLinked(int capacity) throws InterruptedException { LinkedBlockingQueue<Bread> queue = new LinkedBlockingQueue<Bread>(capacity); CountDownLatch cdl = new CountDownLatch(10); ExecutorService es = Executors.newFixedThreadPool(10); long start = System.currentTimeMillis(); for(int i = 0; i < 10;i++) { es.submit(new ProducerLinked(queue, cdl)); } cdl.await(); long end = System.currentTimeMillis(); es.shutdown(); System.out.println("put in LinkedBlockingQueue size:="+queue.size() +",use time:="+(end-start)); } }
二、写入及读取性能对比:
package com.dxz.queue.linked; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.CountDownLatch; public class ConsumerArray implements Runnable{ //容器 private final ArrayBlockingQueue<Bread> queue; private final CountDownLatch cdl; private int consumeCount = 0; public ConsumerArray(ArrayBlockingQueue<Bread> queue, CountDownLatch cdl){ this.queue = queue; this.cdl = cdl; } @Override public void run() { while(true){ consume(); } } public void consume(){ /** * take()方法和put()方法是对应的,从中拿一个数据,如果拿不到线程挂起 * poll()方法和offer()方法是对应的,从中拿一个数据,如果没有直接返回null */ try { //Bread bread = queue.take(); while(consumeCount<1000000) { if(null !=queue.poll()) { consumeCount++; // System.out.println(consumeCount); } } cdl.countDown(); } catch (Exception e) { e.printStackTrace(); } } } package com.dxz.queue.linked; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.CountDownLatch; import java.util.concurrent.LinkedBlockingQueue; public class ConsumerLinked implements Runnable{ //容器 private final LinkedBlockingQueue<Bread> queue; private final CountDownLatch cdl; private int consumeCount = 0; public ConsumerLinked(LinkedBlockingQueue<Bread> queue, CountDownLatch cdl){ this.queue = queue; this.cdl = cdl; } @Override public void run() { while(true){ consume(); } } public void consume(){ /** * take()方法和put()方法是对应的,从中拿一个数据,如果拿不到线程挂起 * poll()方法和offer()方法是对应的,从中拿一个数据,如果没有直接返回null */ try { //Bread bread = queue.take(); while(consumeCount<1000000) { if(null !=queue.poll()) { consumeCount++; // System.out.println(consumeCount); } } cdl.countDown(); } catch (Exception e) { e.printStackTrace(); } } } package com.dxz.queue.linked; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; public class ClientPutAndTake { public static void main(String[] args) throws InterruptedException { int capacity = 10; //testArray(capacity); //put in ArrayBlockingQueue size:=0,and consumed. use time:=3227 testLinked(capacity); //put in LinkedBlockingQueue size:=0,and consumed. use time:=459 } private static void testArray(int capacity) throws InterruptedException { ArrayBlockingQueue<Bread> queue = new ArrayBlockingQueue<Bread>(capacity); CountDownLatch cdl = new CountDownLatch(11); ExecutorService es = Executors.newFixedThreadPool(10); long start = System.currentTimeMillis(); for(int i = 0; i < 10;i++) { es.submit(new ProducerArray(queue, cdl)); } Thread consumerThread = new Thread(new ConsumerArray(queue, cdl)); consumerThread.setDaemon(true); consumerThread.start(); cdl.await(); long end = System.currentTimeMillis(); es.shutdown(); System.out.println("put in ArrayBlockingQueue size:="+queue.size() +",and consumed. use time:="+(end-start)); } private static void testLinked(int capacity) throws InterruptedException { LinkedBlockingQueue<Bread> queue = new LinkedBlockingQueue<Bread>(capacity); CountDownLatch cdl = new CountDownLatch(11); ExecutorService es = Executors.newFixedThreadPool(10); long start = System.currentTimeMillis(); for(int i = 0; i < 10;i++) { es.submit(new ProducerLinked(queue, cdl)); } Thread consumerThread = new Thread(new ConsumerLinked(queue, cdl)); consumerThread.setDaemon(true); consumerThread.start(); cdl.await(); cdl.await(); long end = System.currentTimeMillis(); es.shutdown(); System.out.println("put in LinkedBlockingQueue size:="+queue.size() +",and consumed. use time:="+(end-start)); } }
阻塞队列的容量越小,冲突概率越大,性能差异越明显。