测试代码:
package com.demo.queue;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
public class ArrayBlockingQueueVsLinkedBlockingQueue {
//任务数量
public static int TASK_SUM = 0;
//生产者/消费者线程数
public static int THREAD_NUM = 0;
//队列大小
public static int QUE_SIZE = 0;
/**
*测试方法
*/
public void test(final BlockingQueue<String> q) throws InterruptedException {
//生产者线程
class Producer implements Runnable {
@Override
public void run() {
for (int i = 0; i < TASK_SUM; i++) {
try {
q.put("task");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
;
//消费者线程
class Consumer implements Runnable {
@Override
public void run() {
for (int i = 0; i < TASK_SUM; 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("任务数量="+ArrayBlockingQueueVsLinkedBlockingQueue.TASK_SUM);
System.out.println("生产者和消费者各线程数量="+ArrayBlockingQueueVsLinkedBlockingQueue.THREAD_NUM);
System.out.println("队列大小="+ArrayBlockingQueueVsLinkedBlockingQueue.QUE_SIZE);
System.out.println(q.getClass().getSimpleName() + " 耗时 : " + (t2 - t1)+"ms");
System.out.println();
}
/**
*主方法
*/
public static void main(String[] args) throws InterruptedException {
//任务数量
ArrayBlockingQueueVsLinkedBlockingQueue.TASK_SUM = 1000000;
//生产者和消费者各多少线程
ArrayBlockingQueueVsLinkedBlockingQueue.THREAD_NUM = 1;
//队列大小
ArrayBlockingQueueVsLinkedBlockingQueue.QUE_SIZE = 100;
final BlockingQueue<String> q1 = new LinkedBlockingQueue<String>(ArrayBlockingQueueVsLinkedBlockingQueue.QUE_SIZE );
final BlockingQueue<String> q2 = new ArrayBlockingQueue<String>(ArrayBlockingQueueVsLinkedBlockingQueue.QUE_SIZE );
new ArrayBlockingQueueVsLinkedBlockingQueue().test(q1);
new ArrayBlockingQueueVsLinkedBlockingQueue().test(q2);
}
}
测试结果1:
任务数量=1000000
生产者和消费者各线程数量=1
队列大小=100
LinkedBlockingQueue 耗时 : 569ms
任务数量=1000000
生产者和消费者各线程数量=1
队列大小=100
ArrayBlockingQueue 耗时 : 560ms
测试结果2:
任务数量=1000000
生产者和消费者各线程数量=1
队列大小=1000
LinkedBlockingQueue 耗时 : 454ms
任务数量=1000000
生产者和消费者各线程数量=1
队列大小=1000
ArrayBlockingQueue 耗时 : 418ms
测试结果3:
任务数量=1000000
生产者和消费者各线程数量=10
队列大小=100
LinkedBlockingQueue 耗时 : 4253ms
任务数量=1000000
生产者和消费者各线程数量=10
队列大小=100
ArrayBlockingQueue 耗时 : 10053ms
测试结果4:
任务数量=1000000
生产者和消费者各线程数量=10
队列大小=1000
LinkedBlockingQueue 耗时 : 3655ms
任务数量=1000000
生产者和消费者各线程数量=10
队列大小=1000
ArrayBlockingQueue 耗时 : 3508ms
测试结果5:
任务数量=1000000
生产者和消费者各线程数量=30
队列大小=1000
LinkedBlockingQueue 耗时 : 10417ms
任务数量=1000000
生产者和消费者各线程数量=30
队列大小=1000
ArrayBlockingQueue 耗时 : 9432ms
测试结果6:
任务数量=1000000
生产者和消费者各线程数量=30
队列大小=5000
LinkedBlockingQueue 耗时 : 10449ms
任务数量=1000000
生产者和消费者各线程数量=30
队列大小=5000
ArrayBlockingQueue 耗时 : 5600ms
测试结果7:
任务数量=1000000
生产者和消费者各线程数量=100
队列大小=5000
LinkedBlockingQueue 耗时 : 33265ms
任务数量=1000000
生产者和消费者各线程数量=100
队列大小=5000
ArrayBlockingQueue 耗时 : 21303ms
总结:
原因分析:
共同点好理解,线程多,并发大,互相争抢,协调资源需要时间,所以降低了效率。增加队列容量,相当于增大了缓冲,有益于提高性能;
但为什么ArrayBlockingQueue 性能更好,我没分析出来,有请大佬评论;
修改代码,使生产者和消费者线程数量不同
package com.demo.queue;
import com.sun.deploy.util.StringUtils;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public class ArrayBlockingQueueVsLinkedBlockingQueue {
//任务数量
public static int TASK_SUM = 0;
//生产者/消费者线程数
public static int CONSUME_THREAD_NUM = 0;
public static int PRODUCE_THREAD_NUM = 0;
//队列大小
public static int QUE_SIZE = 0;
/**
*测试方法
*/
public void test(final BlockingQueue<String> queue) throws InterruptedException {
//生产者线程
class Producer implements Runnable {
@Override
public void run() {
for (int i = 0; i < TASK_SUM; i++) {
try {
queue.put("task");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
;
AtomicInteger counter = new AtomicInteger(0);
//消费者线程
class Consumer implements Runnable {
@Override
public void run() {
while(true){
if(counter.get()>=TASK_SUM*PRODUCE_THREAD_NUM){
return;
}
try {
String poll = queue.poll(1, TimeUnit.MICROSECONDS);
if(poll!=null){
counter.incrementAndGet();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
;
//创建生产者
Thread[] arrProducerThread = new Thread[PRODUCE_THREAD_NUM];
for (int i = 0; i < PRODUCE_THREAD_NUM; i++) {
arrProducerThread[i] = new Thread(new Producer());
}
//创建消费者
Thread[] arrConsumerThread = new Thread[CONSUME_THREAD_NUM];
for (int i = 0; i < CONSUME_THREAD_NUM; i++) {
arrConsumerThread[i] = new Thread(new Consumer());
}
//go!
long t1 = System.currentTimeMillis();
for (int i = 0; i < CONSUME_THREAD_NUM; i++) {
arrConsumerThread[i].start();
}
for (int i = 0; i < PRODUCE_THREAD_NUM; i++) {
arrProducerThread[i].start();
}
//等待完成
for (int i = 0; i < CONSUME_THREAD_NUM; i++) {
arrConsumerThread[i].join();
}
for (int i = 0; i < PRODUCE_THREAD_NUM; i++) {
arrProducerThread[i].join();
}
long t2 = System.currentTimeMillis();
System.out.println("任务数量="+TASK_SUM);
System.out.println("生产者各线程数量="+PRODUCE_THREAD_NUM);
System.out.println("消费者各线程数量="+CONSUME_THREAD_NUM);
System.out.println("队列大小="+QUE_SIZE);
System.out.println("执行完毕的任务数量="+counter.get());
System.out.println(queue.getClass().getSimpleName() + " 耗时 : " + (t2 - t1)+"ms");
System.out.println();
}
/**
*主方法
*/
public static void main(String[] args) throws InterruptedException {
//任务数量
ArrayBlockingQueueVsLinkedBlockingQueue.TASK_SUM = 1000000;
//生产者和消费者各多少线程
ArrayBlockingQueueVsLinkedBlockingQueue.PRODUCE_THREAD_NUM = 1;
ArrayBlockingQueueVsLinkedBlockingQueue.CONSUME_THREAD_NUM = 1;
//队列大小
ArrayBlockingQueueVsLinkedBlockingQueue.QUE_SIZE = 100;
final BlockingQueue<String> q1 = new LinkedBlockingQueue<String>(ArrayBlockingQueueVsLinkedBlockingQueue.QUE_SIZE );
final BlockingQueue<String> q2 = new ArrayBlockingQueue<String>(ArrayBlockingQueueVsLinkedBlockingQueue.QUE_SIZE );
new ArrayBlockingQueueVsLinkedBlockingQueue().test(q1);
new ArrayBlockingQueueVsLinkedBlockingQueue().test(q2);
}
}
测试结果1:
都是单线程,ArrayBlockingQueue 相对较快
任务数量=1000000
生产者各线程数量=1
消费者各线程数量=1
队列大小=100
执行完毕的任务数量=1000000
LinkedBlockingQueue 耗时 : 267ms
任务数量=1000000
生产者各线程数量=1
消费者各线程数量=1
队列大小=100
执行完毕的任务数量=1000000
ArrayBlockingQueue 耗时 : 203ms
测试结果2:
一个生产者,10个消费者,LinkedBlockingQueue耗时稍微上涨。ArrayBlockingQueue 耗时上涨较多。
任务数量=1000000
生产者各线程数量=1
消费者各线程数量=10
队列大小=100
执行完毕的任务数量=1000000
LinkedBlockingQueue 耗时 : 321ms
任务数量=1000000
生产者各线程数量=1
消费者各线程数量=10
队列大小=100
执行完毕的任务数量=1000000
ArrayBlockingQueue 耗时 : 919ms
测试结果3:
10个生产者,10个消费者,队列大小100,耗时都剧增,ArrayBlockingQueue 耗时是LinkedBlockingQueue 的3倍。
任务数量=1000000
生产者各线程数量=10
消费者各线程数量=10
队列大小=100
执行完毕的任务数量=10000000
LinkedBlockingQueue 耗时 : 2208ms
任务数量=1000000
生产者各线程数量=10
消费者各线程数量=10
队列大小=100
执行完毕的任务数量=10000000
ArrayBlockingQueue 耗时 : 6620ms
测试结果4:
10个生产者,10个消费者,加大队列容量到1000,两者耗时相对之前有所下降。ArrayBlockingQueue 耗时较少。
任务数量=1000000
生产者各线程数量=10
消费者各线程数量=10
队列大小=1000
执行完毕的任务数量=10000000
LinkedBlockingQueue 耗时 : 1860ms
任务数量=1000000
生产者各线程数量=10
消费者各线程数量=10
队列大小=1000
执行完毕的任务数量=10000000
ArrayBlockingQueue 耗时 : 1459ms
测试结果5:
10个生产者,20个消费者,队列容量还是1000。LinkedBlockingQueue 耗时基本不变。ArrayBlockingQueue 耗时增加,且大于LinkedBlockingQueue ;
任务数量=1000000
生产者各线程数量=10
消费者各线程数量=20
队列大小=1000
执行完毕的任务数量=10000000
LinkedBlockingQueue 耗时 : 1845ms
任务数量=1000000
生产者各线程数量=10
消费者各线程数量=20
队列大小=1000
执行完毕的任务数量=10000000
ArrayBlockingQueue 耗时 : 2100ms
测试结果6:
20个生产者,10个消费者,队列大小还是1000。两者耗时都剧增。ArrayBlockingQueue 耗时更大。
任务数量=1000000
生产者各线程数量=20
消费者各线程数量=10
队列大小=1000
执行完毕的任务数量=20000000
LinkedBlockingQueue 耗时 : 3752ms
任务数量=1000000
生产者各线程数量=20
消费者各线程数量=10
队列大小=1000
执行完毕的任务数量=20000000
ArrayBlockingQueue 耗时 : 5121ms
总结:
LinkedBlockingQueue 更适合生产者数量少于消费者的情况;
ArrayBlockingQueue 更适合队列容量大的情况;
生产者数量少于消费者时候,两者效率都会更高。
并发越小,两者效率越高。