ThreadPoolExecutor 中的死锁

2022-09-04 22:13:50

遇到一种情况,当所有线程都在函数中等待时,工作队列为空。ThreadPoolExecutorexecute(Runnable)ThreadPoolgetTask

有人有什么想法吗?

是使用 和 创建的ThreadPoolExecutorArrayBlockingQueuecorePoolSize == maximumPoolSize = 4

[编辑]更准确地说,线程在函数中被阻塞。它有要执行的任务,但不执行。ThreadPoolExecutor.exec(Runnable command)

[编辑2]执行程序在工作队列 () 中的某个位置被阻止。ArrayBlockingQueue

[编辑3]调用堆栈:

thread = front_end(224)
at sun.misc.Unsafe.park(Native methord)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:158)
at
java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:747)
at
java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:778)
at
java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1114)
at
java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:186)
at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:262)
at java.util.concurrent.ArrayBlockingQueue.offer(ArrayBlockingQueue.java:224)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:653)
at net.listenThread.WorkersPool.execute(WorkersPool.java:45)

同时工作队列为空(使用远程调试进行检查)

[编辑4]代码使用 :ThreadPoolExecutor

public WorkersPool(int size) {
  pool = new ThreadPoolExecutor(size, size, IDLE_WORKER_THREAD_TIMEOUT, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(WORK_QUEUE_CAPACITY),
      new ThreadFactory() {
        @NotNull
        private final AtomicInteger threadsCount = new AtomicInteger(0);

        @NotNull
        public Thread newThread(@NotNull Runnable r) {
          final Thread thread = new Thread(r);
          thread.setName("net_worker_" + threadsCount.incrementAndGet());
          return thread;
        }
      },

      new RejectedExecutionHandler() {
        public void rejectedExecution(@Nullable Runnable r, @Nullable ThreadPoolExecutor executor) {
          Verify.warning("new task " + r + " is discarded");
        }
      });
  }

  public void execute(@NotNull Runnable task) {
    pool.execute(task);
  }

  public void stopWorkers() throws WorkersTerminationFailedException {
    pool.shutdownNow();
    try {
      pool.awaitTermination(THREAD_TERMINATION_WAIT_TIME, TimeUnit.SECONDS);
    } catch (InterruptedException e) {
      throw new WorkersTerminationFailedException("Workers-pool termination failed", e);
    }
  }
}

答案 1

这听起来像是一个JVM早于6u21的错误。对于某些(可能是所有)操作系统,编译的本机代码中存在问题。

从链接:

该错误是由各种Parker::p ark()路径中缺少内存屏障引起的,这些障碍可能导致丢失唤醒和挂起。(请注意,平台事件::p内置同步使用的方舟不容易受到此问题的影响)。-XX:+UseMembar 构成了一个解决方法,因为状态转换逻辑中的 membar 屏障隐藏了 Parker:: 中的问题。(也就是说,使用-UseMembar机制没有错,但是+UseMembar隐藏了Parker::)的错误。这是在 JDK 5.0 中添加 java.util.concurrent 后引入的一个第一天的错误。我开发了一个简单的C模式的故障,它似乎更有可能在现代AMD和Nehalem平台上表现出来,可能是因为更深的存储缓冲区需要更长的时间才能耗尽。我为Parker::p ark提供了Doug Lea的暂定修复,这似乎消除了这个错误。我将向运行时提供此修补程序。(我还将通过其他测试用例和更长的解释来增强CR)。这可能是后退端口的良好候选者。

链接: JVM 错误

有解决方法可用,但您可能最好只获取最新的Java副本。


答案 2

我没有在 的代码中看到任何锁定。唯一的变量是 .你提供了什么样的?ThreadPoolExecutorexecute(Runnable)workQueueBlockingQueueThreadPoolExecutor

关于死锁的话题:

您可以通过检查 Windows 或 UNIX 系统上提供的全线程转储来确认这是死锁。<ctrl><break>kill -QUIT

获得该数据后,可以检查线程。以下是Sun关于检查线程转储的文章的相关摘录(建议阅读):

对于挂起、死锁或冻结的程序:如果您认为程序挂起,请生成堆栈跟踪并检查状态为 MW 或 CW 的线程。如果程序死锁,那么一些系统线程可能会显示为当前线程,因为JVM没有其他事情可做。

更轻松的一点是:如果在IDE中运行,是否可以确保这些方法中没有启用断点。


推荐