遇到ThreadPoolExecutor
函数停留在execute(Runnable)
函数中且所有ThreadPool
个线程都在getTask
func中等待的情况时,workQueue为空。
有人有什么想法吗?
使用ThreadPoolExecutor
和ArrayBlockingQueue
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)
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)
同时workQueue为空(使用远程调试检查)
[Edit4]代码使用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);
}
}
}
答案 0 :(得分:7)
听起来这是一个JVM早于6u21的错误。某些(可能是所有)操作系统的编译本机代码存在问题。
从链接:
该错误是由各种Parker :: park()中缺少内存障碍引起的 可能导致唤醒和挂起丢失的路径。 (注意 内置同步使用的PlatformEvent :: park不容易受到攻击 问题)。 -XX:+ UseMembar构成一个解决方法,因为 状态转换逻辑中的膜屏障隐藏了问题 帕克::。 (也就是说,使用-UseMembar没有任何问题 机制,但+ UseMembar隐藏了Parker::)的bug。这是第一天 在JDK 5.0中添加了java.util.concurrent引入的bug。 我开发了一个简单的C模式的失败,似乎更有可能 在现代AMD和Nehalem平台上体现,可能是因为更深层次 存储缓冲区需要更长时间才能耗尽。我提供了一个暂定的解决方案 到Doug Lea的Parker :: park这似乎消除了这个bug。生病 将此修复程序提供给运行时。 (我还会增加CR 额外的测试用例和更长的解释)。这可能是一个 适合后端的候选人。
链接:JVM Bug
可以使用变通方法,但最好只获取最新的Java副本。
答案 1 :(得分:2)
我看不到ThreadPoolExecutor
的{{1}}代码中的任何锁定。唯一的变量是execute(Runnable)
。您为workQueue
提供了什么BlockingQueue
?
关于死锁的主题:
您可以通过检查Windows上的ThreadPoolExecutor
或UNIX系统上的<ctrl><break>
提供的完整线程转储来确认这是一个死锁。
获得该数据后,您可以检查线程。以下是Sun's article on examining thread dumps (suggested reading)的相关摘录:
对于挂起,死锁或冻结程序:如果您认为程序挂起,则生成堆栈跟踪并检查状态MW或CW中的线程。如果程序死锁,那么一些系统线程可能会显示为当前线程,因为JVM没有其他任何东西可以做。
更轻松的说明:如果您在IDE中运行,可以确保在这些方法中没有启用断点。
答案 2 :(得分:1)
这种死锁可能是因为你从执行者本身运行任务。例如,您提交了一个任务,而这个任务会激活另外4个任务。如果你的池大小等于4,那么你只是完全溢出它,最后一个任务将等到任务返回值。但是第一个任务等待所有分叉任务完成。
答案 3 :(得分:0)
正如有人已经提到的,这听起来像是正常的行为,ThreadPoolExecutor只是在等待做一些工作。如果你想停止它,你需要打电话:
executor.shutdown()
让它终止,通常后跟executor.awaitTermination
答案 4 :(得分:0)
图书馆代码来源如下(实际上是来自http://spymemcached.googlecode.com/files/memcached-2.4.2-sources.zip的班级),
- 有点复杂 - 如果我没有弄错的话,可以防止重复调用FutureTask - 但似乎不容易出现死锁 - 非常简单的ThreadPool用法:
package net.spy.memcached.transcoders;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
import net.spy.memcached.CachedData;
import net.spy.memcached.compat.SpyObject;
/**
* Asynchronous transcoder.
*/
public class TranscodeService extends SpyObject {
private final ThreadPoolExecutor pool = new ThreadPoolExecutor(1, 10, 60L,
TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(100),
new ThreadPoolExecutor.DiscardPolicy());
/**
* Perform a decode.
*/
public <T> Future<T> decode(final Transcoder<T> tc,
final CachedData cachedData) {
assert !pool.isShutdown() : "Pool has already shut down.";
TranscodeService.Task<T> task = new TranscodeService.Task<T>(
new Callable<T>() {
public T call() {
return tc.decode(cachedData);
}
});
if (tc.asyncDecode(cachedData)) {
this.pool.execute(task);
}
return task;
}
/**
* Shut down the pool.
*/
public void shutdown() {
pool.shutdown();
}
/**
* Ask whether this service has been shut down.
*/
public boolean isShutdown() {
return pool.isShutdown();
}
private static class Task<T> extends FutureTask<T> {
private final AtomicBoolean isRunning = new AtomicBoolean(false);
public Task(Callable<T> callable) {
super(callable);
}
@Override
public T get() throws InterruptedException, ExecutionException {
this.run();
return super.get();
}
@Override
public T get(long timeout, TimeUnit unit) throws InterruptedException,
ExecutionException, TimeoutException {
this.run();
return super.get(timeout, unit);
}
@Override
public void run() {
if (this.isRunning.compareAndSet(false, true)) {
super.run();
}
}
}
}
答案 5 :(得分:0)
绝对奇怪。
但在编写自己的TPE之前,请尝试:
另一个BlockingQueue
impl。,例如LinkedBlockingQueue
在ArrayBlockingQueue中指定fairness = true,即使用new ArrayBlockingQueue(n, true)
从这两个选项中我会选择第二个'因为offer()
被阻挡是非常奇怪的;我想到的一个原因 - Linux上的线程调度策略。就像一个假设。