性能上的同步与重入锁定

在针对multithreading系统的Queue实现时,我遇到了一些惊喜。 这是:-

场景: – 1个生产者,1个消费者: – 生产者将整数放入队列中。 消费者只是将其从队列中删除。

队列的基础数据结构: – TreeSet(我从未想过会使用),LinkedList,LinkedBlockingQueue(具有不确定的大小)

代码: – TreeSet作为队列: –

while (i  0)) { try { objQueue.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } Integer x = objQueue.first(); if (x != null) { objQueue.remove(x); ++i; } } } 

编辑:-

  while (i < 2000000) { synchronized (objQueue) { objQueue.add(i); ++i; objQueue.notify(); } } 

对于LinkedBlockingQueue: –

  while (i < 2000000){ try { objQueue.put(i); ++i; } catch (InterruptedException e) { // TODO Auto-generated catch block Thread.currentThread().interrupt(); } } while (i < 2000000) { try { objQueue.take(); ++i; } catch (InterruptedException e) { // TODO Auto-generated catch block Thread.currentThread().interrupt(); } } 

对于LinkedList: – 类似的代码与synchronized。

问题: –

1)当我通过Visual VM测量性能时,我发现对于生产者代码,TreeSet比LinkedBlockingQueue和LinkedList表现更好,即使它需要O(log n)时间,在Linked结构中创建对象也是一个重要的开销。 为什么理论与实践有很大不同? 为什么我们更喜欢在队列实现中使用Tree结构的Linked,Array结构?

2)同步作为一个明显的胜利者与ReeentrantLock相比,因为TreeSet的表现优于LinkedList,其表现优于LinkedBlockingQueue。 我希望我可以附加Visual VM结果。 它不是与文章投票, http://www.ibm.com/developerworks/java/library/j-jtp10264/index.html

执行操作

戴尔Vostro 1015,核心2双核2.10,2GB Ram,32位操作系统和

JVM:Java HotSpot(TM)客户端VM(20.1-b02,混合模式)Java:版本1.6.0_26,供应商Sun Microsystems Inc.

1.如果需要实现遍历链表的线程,锁定下一个节点然后解锁当前节点,则可能更容易使用ReentrantLock

2. Synchronized关键字适用于锁定粗化,提供自适应旋转,偏置锁定以及通过逃逸分析锁定省略的可能性 。 ReentrantLock目前尚未实现这些优化。

要进行适当的性能比较,请看:

http://lycog.com/concurency/performance-reentrantlock-synchronized/

  1. 因为您的基准测试存在缺陷:在实际用例中,从队列中生成和使用元素所花费的时间比向队列添加元素和从队列中删除元素所花费的时间要重要得多。 所以队列的原始性能并不那么重要。 顺便说一下,代码只显示了如何从第一个队列实现中获取元素,而不是如何添加元素。 而且,选择适当的结构不是基于性能,而是基于行为。 如果你想要并发的东西,你选择一个阻塞队列,因为它是为你实现的,并没有像你的代码那样的bug。 如果您想要FIFO(通常是您想要的),您将不会选择TreeSet。

  2. 如果要比较synchronized和ReentrantLock,则不应将一个数据结构用于一个,另一个数据结构用于另一个。 ReentrantLock曾经更快,但现在它们处于同一水平(如果我相信Brian Goetz在JCIP中所说的话)。 无论如何,出于安全/能力原因,我会选择一个而不是另一个。 不是出于性能原因。