ArrayBlockingQueue 和 LinkedBlockingQueue 效能測試與分析

阿拉的夢想發表於2020-11-27

ArrayBlockingQueue 和 LinkedBlockingQueue 效能測試

測試程式碼:

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

總結:

  1. 總的來看,ArrayBlockingQueue 要比LinkedBlockingQueue 效率高;網上說LinkedBlockingQueue 效能更好,但我沒測出來;
  2. 兩者共同點,隨著執行緒增多,併發越大,效率越低;
  3. 兩者共同點,佇列容量越大,效率越高;
  4. 兩者共同點,單執行緒讀寫效率最高;

原因分析:

  1. 共同點好理解,執行緒多,併發大,互相爭搶,協調資源需要時間,所以降低了效率。增加佇列容量,相當於增大了緩衝,有益於提高效能;

  2. 但為什麼ArrayBlockingQueue 效能更好,我沒分析出來,有請大佬評論

相關文章