并发队列对比之二: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));
    }  
  
}

阻塞队列的容量越小,冲突概率越大,性能差异越明显。

posted on 2012-10-11 15:57  duanxz  阅读(1799)  评论(0编辑  收藏  举报