【问题标题】:Is "Thread starvation deadlock" happening here“线程饥饿死锁”是否发生在这里
【发布时间】:2012-10-12 09:57:37
【问题描述】:

我正在尝试使用 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,并且处理正常。感谢 cmets 的 Marko。 问题仍然是,是什么让池中的 50 个并发任务而不是 10 个并发任务?

非常感谢

【问题讨论】:

  • 看来问题出在engine.processTx(transaction)...
  • 作为一般建议,使用那么多并行服务调用几乎肯定无法提高性能。我希望性能在 10 个并发请求时或之前趋于平稳。

标签: java multithreading deadlock


【解决方案1】:

我在您提供的代码中没有发现问题。

我不会猜测可能挂起的位置,而是使用jstackjvisualvm 获取堆栈跟踪,并找到挂起线程的行和堆栈跟踪以及它们共享的对象。

【讨论】:

    【解决方案2】:

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

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


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

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

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

    【讨论】:

    • 谢谢,我编辑了我的问题,如果你能看看就好了
    • 谢谢你,我明白你的意思了,但我还是很困惑。它无法控制 API,我在每次调用时创建 Engine 的新实例。我只是想确保 API 部分负责“无法处理这么多的同时事务”。
    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        猜你喜欢
        • 2021-06-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-07-26
        • 1970-01-01
        • 2014-03-13
        • 1970-01-01
        相关资源
        最近更新 更多