对象创建是多线程环境中Java的瓶颈吗?

时间:2011-02-20 00:08:07

标签: java multithreading memory-management

基于以下理解:

Where is allocated variable reference, in stack or in the heap?

我想知道因为所有对象都是在公共堆上创建的。如果多个线程创建对象然后为了防止数据损坏,必须进行一些必须发生的序列化以防止多个线程在相同位置创建对象。现在,有了大量的线程,这种序列化将导致一个巨大的瓶颈。 Java如何避免这个瓶颈?或者我错过了什么?

任何帮助表示感谢。

3 个答案:

答案 0 :(得分:12)

现代虚拟机实现为每个线程保留堆上的一个自己的区域来创建对象。所以,只要这个区域没有填满(然后垃圾收集器移动幸存的对象)就没问题了。

进一步阅读:Sun的JVM中的how TLAB worksAzul's VM使用稍微不同的方法(查看“新线程和堆栈布局”),文章展示了JVM可能在幕后执行的一些技巧,以确保现在的Java速度。

主要思想是保持每个线程(非共享)区域分配新对象,就像使用C / C ++在堆栈上分配一样。复制垃圾收集非常快速地释放短期对象,少数幸存者(如果有的话)被移动到不同的区域。因此,创建相对较小的对象非常快且 lock free

无锁分配非常重要,特别是因为问题涉及multithreaded environment。它还允许存在真正的无锁算法。即使算法本身是无锁的,但新对象的分配是同步的,整个算法也是有效同步的,并且最终可扩展性较差。 基于work of Maged M. Michael Michael L. Scottjava.util.concurrent.ConcurrentLinkedQueue是一个典型的例子。


如果某个对象被另一个线程引用会发生什么? (由于讨论要求)

该对象(称之为A)将被移动到某个“幸存者”区域。幸存区域的检查频率低于ThreadLocal区域。它包含,如名称所示,其引用设法逃脱的对象,或特别是A设法保持活着。复制(移动)部分发生在某些“安全点”(安全点排除了正确的JIT代码),因此垃圾收集器确保该对象未被引用。更新对象的引用,发布必要的内存围栏,应用程序(java代码)可以继续。进一步阅读simplistic scenario

对于非常感兴趣的读者,如果可能的话,咀嚼它:高度先进的Pauseless GC Algorithm

答案 1 :(得分:1)

没有。 JVM有各种各样的技巧,以避免在“新”时出现任何类型的简单序列化。

答案 2 :(得分:1)

有时。我写了一个递归方法,生成整数排列并从中创建对象。该方法的多线程版本(来自root = task的每个分支,但并发线程数限制为核心数)并不快。并且CPU负载不高。任务没有共享任何对象。从两种方法中删除对象后,多线程方法的速度提高了约4倍(6个核心)并使用了100%的CPU。在我的测试用例中,这些方法产生了大约4,500,000个排列,每个任务1500个。 我认为TLAB不起作用,因为它的空间有限(参见:Thread Local Allocation Buffers)。