ThreadPoolExecutor中的死锁 [英] Deadlock in ThreadPoolExecutor

查看:882
本文介绍了ThreadPoolExecutor中的死锁的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

遇到当 ThreadPoolExecutor 停留在 execute(Runnable)函数中时所有 ThreadPool 线程正在等待 getTask func,workQueue为空。



有没有任何想法?



ThreadPoolExecutor 是使用 ArrayBlockingQueue code> corePoolSize == maximumPoolSize = 4



更多精确的线程在 ThreadPoolExecutor.exec(Runnable command) func。



[Edit2]执行器被阻塞在工作队列内的某处( ArrayBlockingQueue )。



[Edit3] callstack:

  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)
在java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:262)
在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)

同时workQueue为空(使用远程调试检查)



[Edit4]代码使用 ThreadPoolExecutor

  public WorkersPool ){
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 (新任务+ r +被丢弃);
}
});
}

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(Worker-pool termination failed,e);
}
}
}


解决方案>

听起来这是一个JVM比6u21更老的bug。



在链接:


该错误是由于各种Parker :: park()
路径中缺少内存障碍而导致的,这些路径可能导致失去的唤醒和挂起。 (注意,内置同步使用的
PlatformEvent :: park不容易受到
的问题的影响)。 -XX:+ UseMembar constitues一种解决方法,因为状态转换逻辑中的
Membar屏障隐藏了
Parker ::中的问题。 (也就是说,使用-UseMembar
机制没有问题,但是+ UseMembar隐藏了错误Parker::)。这是一个一天的
错误,在JDK 5.0中添加了java.util.concurrent。
我开发了一个简单的C模式的故障,似乎更可能
在现代AMD和Nehalem平台上显示,可能是因为更深的
存储缓冲区需要更长的时间耗尽。我向Doug Lea提供了一个临时修正
,用于Parker :: park,看起来可以消除这个bug。我将
提供这个修复运行时。 (我也将增加CR与
额外的测试用例和更长的解释)。这可能是一个
好​​的候选人用于后端。


链接: JVM Bug



解决方法是可用的,但你可能是最好的最新的Java副本。


Encountered a situation when ThreadPoolExecutor is parked in execute(Runnable) function while all the ThreadPool threads are waiting in getTask func, workQueue is empty.

Does anybody have any ideas?

The ThreadPoolExecutor is created with ArrayBlockingQueue, and corePoolSize == maximumPoolSize = 4

[Edit] To be more precise, the thread is blocked in ThreadPoolExecutor.exec(Runnable command) func. It has the task to execute, but doesn't do it.

[Edit2] The executor is blocked somewhere inside the working queue (ArrayBlockingQueue).

[Edit3] The callstack:

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)

at the same time the workQueue is empty (checked using remote debug)

[Edit4] Code working with 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);
    }
  }
}

解决方案

It sounds like it is a bug with an JVM's older than 6u21. There was an issue in the compiled native code for some (maybe all) OS's.

From the link:

The bug is caused by missing memory barriers in various Parker::park() paths that can result in lost wakeups and hangs. (Note that PlatformEvent::park used by built-in synchronization is not vulnerable to the issue). -XX:+UseMembar constitues a work-around because the membar barrier in the state transition logic hides the problem in Parker::. (that is, there's nothing wrong with the use -UseMembar mechanism, but +UseMembar hides the bug Parker::). This is a day-one bug introduced with the addition of java.util.concurrent in JDK 5.0. I developed a simple C mode of the failure and it seems more likely to manifest on modern AMD and Nehalem platforms, likely because of deeper store buffers that take longer to drain. I provided a tentative fix to Doug Lea for Parker::park which appears to eliminate the bug. I'll be delivering this fix to runtime. (I'll also augment the CR with additional test cases and and a longer explanation). This is likely a good candidate for back-ports.

Link: JVM Bug

Workarounds are available, but you would probably be best off just getting the most recent copy of Java.

这篇关于ThreadPoolExecutor中的死锁的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆