同步与重入锁定性能

2022-09-03 05:30:11

在多线程系统的队列实现方面,我遇到了一些惊喜。这里是:-

场景:- 1 个生产者,1 个消费者:- 生产者将一个整数放入队列中。使用者只需将其从队列中删除即可。

队列的底层数据结构:- TreeSet(我从未想过我会使用),LinkedList,LinkedBlockingQueue(大小不确定)

代码:- 的树集作为队列:-

while (i < 2000000) {
        synchronized (objQueue) {

            if (!(objQueue.size() > 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();
        }
    }

对于链接阻止队列:-

     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 :- 具有同步的类似代码。

问题:-

1)当我通过Visual VM测量性能时,我观察到对于生产者代码,TreeSet的性能优于LinkedBlockingQueue和LinkedList,即使它需要O(log n)时间,在Linked结构中创建对象是一个很大的开销。为什么理论与实践完全不同?为什么在队列实现中,我们更喜欢链接的数组结构而不是树结构?

2)与ReeentrantLock相比,同步显然是赢家,因为TreeSet的表现优于LinkedList,后者的表现优于LinkedBlockingQueue。我希望我可以附加可视 VM 结果。它不是在投票与文章,http://www.ibm.com/developerworks/java/library/j-jtp10264/index.html

操作在

戴尔Vostro 1015,酷睿2双核2.10,2GB内存,带32位操作系统,带

JVM: Java HotSpot(TM) Client VM (20.1-b02, mixed mode) Java: version 1.6.0_26, vendor Sun Microsystems Inc.


答案 1

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

2.关键字适用于锁粗化等情况,通过逃逸分析提供自适应旋转,偏置锁定和锁免的可能性。这些优化目前尚未针对 ReentrantLock 实现。Synchronized

有关适当的性能比较,请参阅以下内容:

https://web.archive.org/web/20201022183359/https://blogs.oracle.com/dave/javautilconcurrent-reentrantlock-vs-synchronized-which-should-you-use


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

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