ArrayBlockingQueue可以像LinkedBlockingQueue那样用两个锁实现吗

基于数组的阻塞队列实现,在ArrayBlockingQueue内部,维护了一个定长数组,以便缓存队列中的数据对象,这是一个常用的阻塞队列,除了一个定长数组外,ArrayBlockingQueue内部还保存着两个整形变量,分别标识着队列的头部和尾部在数组中的位置。
ArrayBlockingQueue在生产者放入数据和消费者获取数据,都是共用同一个锁对象,由此也意味着两者无法真正并行运行,这点尤其不同于LinkedBlockingQueue;
按照实现原理来分析,ArrayBlockingQueue完全可以采用分离锁,从而实现生产者和消费者操作的完全并行运行。之所以没这样去做,猜测是因为ArrayBlockingQueue的数据写入和获取操作已经足够轻巧,以至于引入独立的锁机制,除了给代码带来额外的复杂性外,其在性能上完全占不到任何便宜。 ArrayBlockingQueue和LinkedBlockingQueue间还有一个明显的不同之处在于,前者在插入或删除元素时不会产生或销毁任何额外的对象实例,而后者则会生成一个额外的Node对象。这在长时间内需要高效并发地处理大批量数据的系统中,其对于GC的影响还是存在一定的区别。而在创建ArrayBlockingQueue时,我们还可以控制对象的内部锁是否采用公平锁,默认采用非公平锁

■网友
array是数组啊,连续的内存空间,,它内部有个reentreenlock,每次take也好,put也好 都会先枷锁在做,可以看作悲观锁吧,link的要好一点,addhead和removetail啊什么的可以同时做,即便同时addhead 也可以优化乐观锁,cas上add错了加锁。。。。。俩锁是啥东西?手机党打字好累。。。客官您老将就看吧。。。。
■网友
首先,ArrayBlockingQueue当然可以像LinkedBlockingQueue那样使用两个ReenTrantLock实现。
为什么没有这么做呢?个人猜想这是设计者考虑到ArrayBlockingQueue底层是使用的数组,而LinkedBlockingQueue底层使用的是链表。
LinkedBlockingQueue添加元素时有一个构造节点的时间,为了尽量减少这部分时间占比,使用一个读锁一个写锁可以实现并发存取的优化。而ArrayBlockingQueue在添加元素时不需要开辟空间等等(创建时指定数组大小),所以反而是加锁解锁时间占比较大,如果继续使用这种读写锁分离的设计,增加的时间损耗大于并发读写带来的收益。

■网友
【ArrayBlockingQueue可以像LinkedBlockingQueue那样用两个锁实现吗】 我觉得还是因为数组的入队和出队时间复杂度低,不像列表需要额外维护节点对象。所以当入队和出队并发执行时,阻塞时间很短。如果使用双锁的话,会带来额外的设计复杂性,如count应被volatile修饰,并且赋值需要CAS操作等。而且ArrayBlockingQueue是定长的,当putIndex==length时,putIndex会重置为0,这样入队和出队的index可能是同一个,在这种情况下还需要考虑锁之间的通讯,参考读写锁。


    推荐阅读