Java的ExecutorService性能

3
我有一个主线程,将任务分配给线程池。我正在使用Java的Executor框架。
从分析器(VirtualVM)中,我可以看到每个线程的活动:我可以看到主线程经常等待(因为执行程序的队列有一个上限),这意味着执行程序的队列大部分时间都是满的。然而,执行程序的线程并不像我想象的那样忙碌。它们中的大多数等待时间为75%。在virtualVM中,它说它在Monitor上等待。
有人能解释一下为什么会发生这种情况吗?为什么执行程序线程会等待,而仍然有大量工作可做?如何提高执行程序的性能?从而提高整体性能?关于执行程序等待监视器的更多详细信息将是很好的。
工作运行在工作者中只是一些计算,不依赖于任何其他东西,也不与任何其他线程通信(没有同步),除了最后,它使用自己的连接将数据放入数据库中。

可能是重复的问题:https://dev59.com/rlrUa4cB1Zd3GeqPkoeX?rq=1 - Michal Borek
1
你正在做什么样的工作?发布Job对象的代码。发布关键部分的代码。 - Dariusz
1
你确定他们在等待工作吗?更有可能的是,他们正在等待其他锁定。 - Gray
1
"it waits on Monitor." => 你似乎正在使用锁或同步语句,这是你的瓶颈... - assylias
有没有办法看到他们在等待哪个监视器?我还怀疑这是执行器的内部监视器。 - Wudong
4个回答

3

如果符合以下情况,与同步执行相比,并行执行将产生显着更好的结果:

  1. 要处理的工作彼此独立(没有或很少且非常短的关键部分)。

  2. 每个单独执行的工作需要足够长的时间来弥补线程启动/执行器内部同步的时间成本。

  3. 工作不使用相同的资源-例如从同一磁盘读取多个文件可能比按顺序读取它们更慢。

  4. 您实际上拥有足够的系统资源(处理器核心、内存、网络速度)可同时使用。


1

线程并不意味着所有线程始终都会并行工作。线程一定会因各种原因进入等待状态,大多数情况下取决于调度程序如何分配CPU给它们中的每一个。您的线程类中是否有同步代码?如果是,则如果一个线程正在执行同步方法,则所有其他线程都必须等待。如果同步代码太多,则线程等待时间将增加。


0

做完线程转储后,发现同步问题出现在数据库层。Hibernate的序列生成器是同步的。

"pool-2-thread-1" - Thread t@13
   java.lang.Thread.State: BLOCKED
    at org.hibernate.id.SequenceHiLoGenerator.generate(SequenceHiLoGenerator.java:73)
    - waiting to lock <61fcb35> (a org.hibernate.id.SequenceHiLoGenerator) owned by "pool-2-thread-5" t@23
    at org.hibernate.internal.StatelessSessionImpl.insert(StatelessSessionImpl.java:117)
    at org.hibernate.internal.StatelessSessionImpl.insert(StatelessSessionImpl.java:110)
    at ac.uk.ebi.kraken.unisave.storage.impl.HibernateStorageEngine.saveEntryIndex(HibernateStorageEngine.java:269)
    at ac.uk.ebi.kraken.unisave.storage.impl.EntryStoreImpl.storeEntryIndex(EntryStoreImpl.java:302)
    at ac.uk.ebi.kraken.unisave.impl.MTEntryIndexLoader$EntryIndexLoader.run(MTEntryIndexLoader.java:129)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
    at java.util.concurrent.FutureTask.run(FutureTask.java:166)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
    at java.lang.Thread.run(Thread.java:679)

   Locked ownable synchronizers:
    - locked <3d360c93> (a java.util.concurrent.ThreadPoolExecutor$Worker)

2
我们无法仅凭您提供的信息猜测出问题所在。只需连接到数据库并解决问题即可。但是随之而来的问题是数据库可能会成为瓶颈... - Dariusz
我不知道Hibernate会做那么愚蠢的事情... 它不是将记录发送并要求数据库为记录计算序列,而是首先请求数据库序列(这需要同步),然后将记录连同序列值一起发送。 - Wudong
它必须以这种方式完成。这使他能够在涉及关系时重新排序事务中的插入操作。 - gizmo

0

线程由调度程序安排以分配CPU周期来运行它们,这意味着如果机器有4个CPU,一次只能并行运行4个线程,因此其他线程必须等待调度程序分配CPU给它们。


1
活跃竞争 CPU 周期的线程将是 RUNNABLE,而不是等待监视器。 - Ralf H
谢谢您纠正我的误解 :) 我找到了一个很棒的Java线程状态机图:http://www.uml-diagrams.org/examples/java-6-thread-state-machine-diagram-example.html - ltebean

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接