我正在尝试通过Web服务(通过它的Java API)同时处理一些事务,使用Callables和ThreadPool
public class CallableTxSender implements Callable<Transaction> {
private Transaction transaction;
private Engine engine;
public CallableTxSender(Transaction transaction, Engine engine) {
this.transaction = transaction;
this.engine= engine;
}
@Override
public Transaction call() throws Exception {
return engine.processTx(transaction);
}
}
其中Engine
- 是进行网络服务调用的Api。
我正在创建一个说50个线程的池;
ExecutorService executorService = Executors.newFixedThreadPool(50);
List<Transaction> transactions = transactionDao.getPaidTxs();
Engine engine= new Engine();
for (Transaction transaction : transactions) {
CallableTxSender txSender = new CallableTxSender(transaction, engine);
executorService.submit(txSender);
}
当我尝试处理100个交易时,它会在前20-30个交易中正常运行,然后在某个地方挂起。我不确定API是否支持同时请求,但它应该。
我想确定的是我的客户部分没问题。你觉得怎么样?
修改:我将池大小减少到10,并且处理正常。感谢评论中的 Marko 。 问题仍然存在,是什么让一个池挂起50个并发任务而不是10?
非常感谢
答案 0 :(得分:1)
我没有在您提供的代码中看到问题。
不是猜测挂起的位置,而是使用jstack
或jvisualvm
获取堆栈跟踪,并找到挂起线程的行和堆栈跟踪以及它们共享的对象。
答案 1 :(得分:1)
当提交给执行程序服务的任务提交其他任务并等待它们完成时,会发生线程饥饿死锁。您的问题代码中没有任何内容表明此处正在发生。
代码的某些其他部分导致线程饥饿死锁并非不可能,但您还应该考虑其他类型死锁的可能性。
问题仍然存在,是什么让一个池挂起50个并发任务而不是10?
不可能肯定地说。然而,一种可能的解释是同时执行更多任务增加了特定锁定场景将发生的可能性。 (类比是生日悖论......)
结果是减少池大小大大降低了死锁的可能性,但你不能确定你完全消除了这个问题。
答案 2 :(得分:0)
如果交易不相互依赖,那么您的代码就可以了。要确保使用newCachedThreadPool而不是newFixedThreadPool。
答案 3 :(得分:0)
ThreadPoolExecutor实现可以帮助您调整线程池大小,workQueue大小和其他各种可扩展性挂钩。 队列大小和最大池大小可以相互交换。当所有corePoolSize线程忙时,新任务将在workQueue中等待,或者创建新线程达到最大池大小。如果workQueue都已满并且最大池线程忙,则提交给执行程序的新任务将被拒绝,其中一个任务拒绝策略将起作用。当workQueue大小很大时,任务应该彼此独立是很重要的。