昨天突然想到一个问题,为什么juc中ArrayBlockingQueue用一个锁(两个condition),而LinkedBlockingQueue用两个锁(两个condition)实现。
这导致了后者可以一边取一边放,而前者不行。
为了探究其设计的原因,产生了如下qa(自己和自己)
Q:为什么ArrayBlockingQueue put和take不能并行?
A:因为put 和 take用同一个reetrantlock实现。
Q:那改成两个reetranLock就可以并行take和put了吗?
A:不行。因为其中count是int而不是AtomicInteger。会因为和无法原子性修改以及编译器重排序导致其他问题。
Q:那修改int成AtomicInteger就可以了吗?
A:。。。大概吧。。。
(实践尝试后。。)
还是不行,因为这样通知的方式也要该,不能直接condition.signal()而要先获得另外一把锁再通知。
Q:那现在可以并行存取了吗?
A:可以了。
Q:那这样修改后效率有提高吗?
A:我试一下。。。(艾玛 太蛋疼了 周一去公司试好了 宿舍的破电脑 哎。。。)
我先猜测,应该没有提高吧(douglea脑残粉- -哈哈哈)
Q:假设没有提高,你觉得原因是什么呢?
A:LinkedBlockingQueue的较大一部分时间需要构造节点,导致较长的等待。所以同时存取有较大优化。
而ArrayBlockingQueue的不用构造节点,加锁和解锁的时间可能占比较大。
转成双锁之后,对比原来的存取操作,需要多竞争两次。一次是Atomic变量的cas操作,另一次是获得另一把锁的通知操作。可能这部分的损耗,已经比并发存取带来收益更大。
Q:那你怎么证明你上述的观点是正确的呢
A:。。。周一去公司自己实现一个,然后测试一下。
好,周一再见- -。