ArrayBlockingQueue, LinkedBlockingQueue, ConcurrentLinkedQueue, RingBuffer

1. ArrayBlockingQueue, LinkedBlockingQueue, ConcurrentLinkedQueue

ArrayBlockingQueue, LinkedBlockingQueue 继承自 BlockingQueue, 他们的特点就是 Blocking, Blocking 特有的方法就是 take() 和 put(), 这两个方法是阻塞方法, 每当队列容量满的时候, put() 方法就会进入wait, 直到队列空出来, 而每当队列为空时, take() 就会进入等待, 直到队列有元素可以 take()

ArrayBlockingQueue, LinkedBlockingQueue 区别在于 ArrayBlockingQueue 必须指定容量, 且可以指定 fair 变量, 如果 fair 为 true, 则会保持 take() 或者 put() 操作时线程的 block 顺序, 先 block 的线程先 take() 或 put(), fair 又内部变量 ReentrantLock 保证

ConcurrentLinkedQueue 通过 CAS 操作实现了无锁的 poll() 和 offer(), 他的容量是动态的, 由于无锁, 所以在 poll() 或者 offer() 的时候 head 与 tail 可能会改变, 所以它会持续的判断 head 与 tail 是否改变来保证操作正确性, 如果改变, 则会重新选择 head 与 tail. 而由于无锁的特性, 他的元素更新与 size 变量更新无法做到原子 (实际上它没有 size 变量), 所以他的 size() 是通过遍历 queue 来获得的, 在效率上是 O(n), 而且无法保证准确性, 因为遍历的时候有可能 queue size 发生了改变.

 

RingBuffer 是 Distruptor 中的一个用来替代 ArrayBlockingQueue 的队列, 它的思想在于长度可控, 且无锁, 只有在 blocking 的时候(没有数据的时候出队, 数据满的时候入队)会自旋. 实现原理是使用一个环形array, 生产者作为 tail, 消费者作为 head, 每生产一次 tail atomic++, 每消费一次 head atomic++, tail 不能超过 head 一圈(array size, 即队列满时 blocking), tail 不能超过自己tail一圈(即不能覆盖未被消费的值), head 不能超过 tail (即无可消费任务时 blocking), head 不能取到空值(取到空值时 blocking). blocking 使用一个 while 自旋来完成, 那么只要生产者消费者的速度相当时, 即可通过 atomicInteger(cas) 保证无锁, 而如果你需要在 blocking 的时候立即返回, 则 while 自旋都可以不需要. 相比于 ArrayBlockingQueue, 它可以绝大部分时间无锁, blocking 自旋, 相比于 concurrentLinkedQueue, 他又能做到长度限制. 代码如下:

public class RingBuffer<T> implements Serializable {

    /**
     *
     */
    private static final long serialVersionUID = 6976960108708949038L;

    private volatile AtomicInteger head;

    private volatile AtomicInteger tail;

    private int length;

    final T EMPTY = null;

    private volatile T[] queue;

    public RingBuffer(Class<T> type, int length){
        this.head = new AtomicInteger(0);
        this.tail = new AtomicInteger(0);
        this.length = length == 0 ? 2 << 16 : length; // 默认2^16  
        this.queue = (T[]) Array.newInstance(type, this.length);
    }

    public void enQueue(T t){
        if(t == null) t= (T) new Object();
        // 阻塞 -- 避免多生成者循环生产同一个节点  
        while(this.getTail() - this.getHead() >= this.length);
        int ctail = this.tail.getAndIncrement();
        while(this.queue[this.getTail(ctail)] != EMPTY); // 自旋  
        this.queue[this.getTail(ctail)] = t;
    }

    public T deQueue(){
        T t = null;
        // 阻塞 -- 避免多消费者循环消费同一个节点  
        while(this.head.get() >= this.tail.get());
        int chead = this.head.getAndIncrement();
        while(this.queue[this.getHead(chead)] == EMPTY); // 自旋  
        t = this.queue[this.getHead(chead)];
        this.queue[this.getHead(chead)] = EMPTY;
        return t;
    }

    public int getHead(int index){
        return index & (this.length - 1);
    }

    public int getTail(int index) {
        return index & (this.length - 1);
    }

    public int getHead() {
        return head.get() & (this.length - 1);
    }

    public int getTail() {
        return tail.get() & (this.length - 1);
    }

    public T[] getQueue() {
        return queue;
    }

    public int getLength() {
        return length;
    }

    public void setLength(int length) {
        this.length = length;
    }

}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值