[英]Java - Thread stuck in “Park” status
我无法同时运行 100 多个线程。 当我进行线程转储时,我注意到其中许多都处于parked status
,即
停车等待 <0x00000000827e1760> (java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)。
该程序在大约 25 个或更少线程的情况下运行良好。 有没有办法确定导致并发锁的原因,和/或防止它? 这是使用 Executor 服务在 200 的固定池大小中运行的。
为缺少代码道歉 - 它是专有的,有很多东西需要改变来混淆它。
您所指的类 (ConditionObject) 用于锁定对象不被多个线程同时访问。 Javadoc没有描述您提到的线程状态,但这是我的猜测:
您锁定的对象被一个线程阻塞了很长时间,以至于其他线程开始堆积在锁上。 一旦持有锁的线程释放它,下一个线程就会继续获取锁。 在那个新线程完成他的工作之前,新线程会堆积在锁后面。
如果我的猜测是正确的,那么可以:
在不知道您的问题域的情况下,我希望以上信息足以为您指明可能对您有所帮助的方向。
您是否在使用某种ThreadPoolExecutor,例如java.util.concurrent.Executors
类提供的那些? 也许您正面临着任务被静默未捕获的异常完成的情况。 转储片段看起来像一个不活动的池线程,获得不活动线程(应该是活动的)的一个原因是抛出异常但被默认线程池实现包围。
LockSupport.park()
在线程池中,等待任务的线程被LockSupport.park();
锁定LockSupport.park();
. 请参阅来自 openjdk 的java.util.concurrent.locks.AbstractQueuedSynchronizer
源代码:
public final void await() throws InterruptedException {
// code omitted
while (!isOnSyncQueue(node)) {
LockSupport.park(this);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
// code omitted
}
这意味着线程正在执行的任务已完成(是否突然),现在线程正在等待另一个任务执行(请参阅java.util.concurrent.ThreadPoolExecutor
openjdk source ):
private Runnable getTask() {
// ...
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take(); <== the thread is blocked here
// ...
}
可以看到,线程在调用workQueue.take();
被锁定了workQueue.take();
.
因此,很快,处于“停放状态”的线程只是在前一个任务完成后等待新任务。
为什么我的任务不再运行?
完成任务的最合理原因是run()
的正常结束。 任务流结束,然后任务由各自的所有者线程释放。 一旦线程释放任务,只要有任务,它就准备好执行另一个任务。
检查这种情况的一种直接方法是在run()
方法的末尾记录一些内容:
class MyRunnable implements Runnable {
public void run() {
while(/*some condition*/) {
// do my things
}
log.info("My Runnable has finished for now!");
}
}
如果记录一条消息还不够,您可以调用另一个对象的方法。
木头下的例外
另一个(最)可能的原因是任务执行期间抛出的未捕获异常。 在线程池中,像这样的未经检查的异常将突然停止方法执行并(出人意料地)被吞入java.util.concurrent.FutureTask
对象中。 为了避免这样的事情,我使用以下习语:
class MyRunnable implements Runnable {
public void run() {
while(/*some condition*/) {
try {
// do my things
} catch (Throwable throwable) {
handle(throwable);
}
}
log.info("My Runnable has finished for now!");
}
private void handle(Throwable throwable) {
// ...
}
}
或者根据我也使用的逻辑/性能要求:
public void run() {
try {
while(/*some condition*/) {
// do my things
}
} catch (Throwable throwable) {
handle(throwable);
}
System.out.println("My Runnable has finished for now!");
}
下面的代码举例说明了这里评论的问题:
package mypocs;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
public class ExceptionSwallowingInThreadPoolsPoC {
public static void main(String[] args) {
ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) Executors.newFixedThreadPool(10);
final Object LOCK = new Object();
threadPoolExecutor.submit(() -> {
while (true) {
synchronized (LOCK) {
System.out.println("Thread 'A' never ends");
}
Thread.sleep(1000L);
}
});
threadPoolExecutor.submit(() -> {
int lifespan = 3;
while (lifespan > 0) {
synchronized (LOCK) {
System.out.println("Thread 'B' is living for " + lifespan + " seconds");
}
lifespan--;
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Thread 'B' finished");
});
threadPoolExecutor.submit(() -> {
int lifespan = 3;
while (lifespan > 0) {
synchronized (LOCK) {
System.out.println("Thread 'C' is living for " + lifespan + " seconds");
}
lifespan--;
if (lifespan < 1) {
throw new RuntimeException("lifespan reached zero");
}
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Thread 'C' finished");
});
while (true) {
try {
Thread.sleep(1000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (LOCK) {
System.out.println("==== begin");
System.out.println("getActiveCount: " + threadPoolExecutor.getActiveCount());
System.out.println("getCompletedTaskCount: " + threadPoolExecutor.getCompletedTaskCount());
System.out.println("getPoolSize: " + threadPoolExecutor.getPoolSize());
System.out.println("==== end");
}
}
}
}
代码应该输出如下内容:
Thread 'A' never ends
Thread 'B' is living for 3 seconds
Thread 'C' is living for 3 seconds
Thread 'C' is living for 2 seconds
==== begin
getActiveCount: 3
getCompletedTaskCount: 0
getPoolSize: 3
==== end
Thread 'B' is living for 2 seconds
Thread 'A' never ends
==== begin
getActiveCount: 3
getCompletedTaskCount: 0
getPoolSize: 3
==== end
Thread 'C' is living for 1 seconds
Thread 'B' is living for 1 seconds
Thread 'A' never ends
Thread 'B' finished
==== begin
getActiveCount: 1
getCompletedTaskCount: 2
getPoolSize: 3
==== end
Thread 'A' never ends
Thread 'A' never ends
...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.