0

我正在尝试使用 Callables 和 ThreadPool 通过 Web 服务(通过它的 Java API)同时处理一些事务

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- 是执行 Web 服务调用的 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,并且处理得很好。感谢评论中的马尔科。问题仍然是,是什么让池挂起 50 个并发任务而不是 10 个?

非常感谢

4

4 回答 4

1

当提交给执行器服务的任务提交其他任务并等待它们完成时,就会发生线程饥饿死锁。您的问题中的代码中没有任何内容表明这里正在发生这种情况。

您的代码的某些其他部分导致线程饥饿死锁并非不可能,但您还应该考虑其他类型的死锁的可能性。


问题仍然是,是什么让池挂起 50 个并发任务而不是 10 个?

无法肯定地说。然而,一种可能的解释是,同时执行更多任务会增加特定锁定场景发生的可能性。(类比是生日悖论......)

推论是减少池大小已经大大降低了死锁的可能性,但你不能确定你已经完全消除了这个问题。

于 2012-10-12T10:34:39.240 回答
1

我在您提供的代码中没有看到问题。

我不会猜测挂起可能在哪里,而是使用jstackor获得堆栈跟踪,jvisualvm并找到挂起线程的行和堆栈跟踪以及它们共享的对象。

于 2012-10-12T10:00:58.427 回答
0

如果事务不相互依赖,那么您的代码就可以了。为确保,请使用 newCachedThreadPool 而不是 newFixedThreadPool。

于 2012-10-12T10:07:26.663 回答
0

java.util.concurrent 中的ThreadPoolExecutor实现可以帮助您调整线程池大小、workQueue 大小和其他各种可扩展性挂钩。队列大小和最大池大小可以相互权衡。当所有 corePoolSize 线程都忙时,新任务将在 workQueue 中等待,或者创建新线程达到最大池大小。如果两个 workQueue 都已满且最大池线程忙,则提交给 Executor 的新任务将被拒绝,并且其中一项任务拒绝策略将发挥作用。当 workQueue 很大时,任务应该相互独立,这一点很重要。

于 2012-10-12T13:18:16.110 回答