title : 每日深耕,勤练不缀之java并发包中的队列比较
ConcurrentLinkedQueue基于CAS的无锁技术,有着更大的吞吐量
而BlockingQueue是完全根据锁实现的。LinkedBlockingQueue不仅有着 notEmpty和notFull两种再入锁的条件变量,而且更加改进了锁操作的粒度,头尾操作用的不同的锁,比ArrayBlockingQueue吞吐量更大一点。
package BingfaQueue;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
//好精美的代码
public class LinkedBlockingQueue {
/**
* Lock held by take, poll,etc
*/
private final ReentrantLock takeLock =new ReentrantLock();
/**
* Wait queue for waiting takes
*/
private final Condition notEmpty =takeLock.newCondition();
/**
* Lock held by put offer,etc
*/
private final ReentrantLock putlock =new ReentrantLock();
/**
* Wait queue for waiting puts
*/
private final Condition notFull =putlock.newCondition();
private AtomicInteger count;
private int capacity;
/**
* 与ArrayBlockingQueue中的实现有所不同,notEmpty、notFull都是同一个再入锁的条件变量,而LinkedBlockingQueue
* 则改进了锁操作的粒度,头尾操作都使用不同的锁,所以其吞吐量会更好一些
*/
public E take() throws InterruptedException{
final E x;
final int c;
final AtomicInteger count =this.count;
final ReentrantLock takeLock =this.takeLock;
takeLock.lockInterruptibly();
try{
while(count.get()==0){
notEmpty.await();
}
x = dequeue();
c = count.getAndDecrement();
if(c>1){
notEmpty.signal();
}
}finally {
takeLock.unlock();
}
if(c == capacity)
signalNotfull();
return x;
}
private void signalNotfull() {
}
private E dequeue() {
return null;
}
}
生产者消费者(并发)利用ArrayBlockingQueue来实现
package BingfaQueue;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class ConsumerProducer {
public static final String EXIT_MSG ="good bye";
public static void main(String[] args) {
//使用较小的队列,以更好地在输出中展现其影响,并发队列使用
/**
* 当初我的消费者,生产者是依托于 wait 与notify()¬ifyall(),这个队列更高级
*/
BlockingQueue<String> queue = new ArrayBlockingQueue<>(3);//也算是一种继承类的语法
Producer producer =new Producer(queue);
Consumer consumer =new Consumer(queue);
new Thread(producer).start();//将其包裹在线程中
new Thread(consumer).start();
}
static class Producer implements Runnable{
private BlockingQueue<String> queue;
public Producer(BlockingQueue<String> q){//构造函数
this.queue =q;
}
@Override
public void run() {//20个线程并发生产,在值为3(实际为四)的队列里
for(int i=0;i<20;i++){
try{
Thread.sleep(5L);
String msg ="Message"+i;
System.out.println("Produced new item"+msg);
queue.put(msg);//努力生产
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try{
System.out.println("time to say goodbye");
queue.put(EXIT_MSG);
} catch (Exception e) {
e.printStackTrace();
}
}
}
static class Consumer implements Runnable{
private BlockingQueue<String> queue;
public Consumer(BlockingQueue<String> q ){
this.queue=q;
}
@Override
public void run() {
try{
String msg;
while(!EXIT_MSG.equalsIgnoreCase((msg=queue.take()))){//消费
System.out.println("Consumed item" +msg);
Thread.sleep(10L);
}
System.out.println("Got exit message,bye!!!");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
以 LinkedBlockingQueue、ArrayBlockingQueue 和 SynchronousQueue 为例,我们一起来分析一下,根据需求可以从很多方面考量:
- 队列边界:ArrayBlockingQueue有明显限制的,而LinkedBlockingQueue则取决于我们是否在创建时指定,而SynchronousQueue则压根没有缓存任何元素
- 空间利用:ArrayBlockingQueue比LinkedBlockingQueue紧凑,因为其不需要创建所谓节点,但是其初始分配阶段需要一段连续的空间,所以初始内存需求更大
- 吞吐量:LinkedBlockingQueue > ArrayBlockingQueue
- 稳定性:ArrayBlockingQueue