java - Java:如何修复挂起的线程?

请注意:我用jclouds标记这个,因为如果您阅读了随后出现的所有问题和评论,我认为这要么是jclouds的错误,要么是对该库的误用。
我有一个可执行的jar,它运行,工作一段时间,在不抛出任何错误/异常的情况下完成工作,然后在应该退出时永远挂起。我用visualvm(注意正在运行的线程)对其进行了分析,并在应用程序挂起的点(在main()方法的末尾)抛出了一个日志语句进行打印。下面是我主要方法的最后一部分:

Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
for(Thread t : threadSet) {
    String daemon = (t.isDaemon()? "Yes" : "No");
    System.out.println("The ${t.getName()} thread is currently running; is it a daemon? ${daemon}.");
}

当我的jar执行此代码时,我看到以下输出:
The com.google.inject.internal.util.Finalizer thread is currently running; is it a daemon? Yes.
The Signal Dispatcher thread is currently running; is it a daemon? Yes.
The RMI Scheduler(0) thread is currently running; is it a daemon? Yes.
The Attach Listener thread is currently running; is it a daemon? Yes.
The user thread 3 thread is currently running; is it a daemon? No.
The Finalizer thread is currently running; is it a daemon? Yes.
The RMI TCP Accept-0 thread is currently running; is it a daemon? Yes.
The main thread is currently running; is it a daemon? No.
The RMI TCP Connection(1)-10.10.99.8 thread is currently running; is it a daemon? Yes.
The Reference Handler thread is currently running; is it a daemon? Yes.
The JMX server connection timeout 24 thread is currently running; is it a daemon? Yes.

我认为我不必担心守护进程(如果我错了,请纠正我),因此将其筛选到非守护进程:
The user thread 3 thread is currently running; is it a daemon? No.
The main thread is currently running; is it a daemon? No.

显然,主线程仍在运行,因为有东西阻止它退出。嗯,user thread 3看起来很有趣。Visualvm告诉我们什么?
这是应用程序挂起时的线程视图(上面的控制台输出正在打印时发生的情况)。hmmmuser thread 3看起来更可疑!
所以在杀死应用程序之前,我做了一个线程转储。这是user thread 3的stacktrace:
"user thread 3" prio=6 tid=0x000000000dfd4000 nid=0x2360 waiting on condition [0x00000000114ff000]
    java.lang.Thread.State: WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0x0000000782cba410> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
        at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2043)
        at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:442)
        at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1068)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
        at java.lang.Thread.run(Thread.java:744)

    Locked ownable synchronizers:
        - None

我以前从来没有分析过其中的一个,所以这对我来说意味着胡言乱语(但对一个训练有素的人来说可能不是!)是的。
关闭应用程序后,Visualvm的时间线每秒停止滴答/递增,我可以在时间线中水平向后滚动到创建user thread 3的位置,并以一个烦人的线程开始它的生活:
但是我不知道如何判断代码中的user thread 3创建位置。所以我问:
我如何才能知道创建user thread 3的是什么,以及创建user thread 3的位置(特别是因为我怀疑它是创建线程的第三方oss库)?
我怎样才能分清,诊断和修复这个挂线?
更新:
这是我的代码,在创建的同时触发:
ExecutorService myExecutor = Executors.newCachedThreadPool();
for(Node node : nodes) {
    BootstrapAndKickTask bootAndKickTask = new BootstrapAndKickTask(node, ctx);
    myExecutor.execute(bootAndKickTask);
}

myExecutor.shutdown();
if(!myExecutor.awaitTermination(15, TimeUnit.MINUTES)) {
    TimeoutException toExc = new TimeoutException("Hung after the 15 minute timeout was reached.");
    log.error(toExc);

    throw toExc;
}

这里还有我的GitHub Gist包含完整的线程转储。

最佳答案

如果你能粘贴你所使用的全部代码,那就太好了。apache jclouds使用两个执行器来执行某些任务,您必须关闭它们。
确保对从jcloudsclose()获得的上下文或api调用ContextBuilder方法。

本文翻译自 https://stackoverflow.com/questions/25560878/

网站遵循 CC BY-SA 4.0 协议,转载或引用请注明出处。

标签 java multithreading concurrency deadlock jclouds


相关文章:

java - Java程序的Cron工作

c# - .NET中的负载测试应遵循哪种方法?

java - 为什么在我的应用程序中按顺序执行Spring DeferredResult?

java - 我从基于Java的AWS lambda处理程序中启动了一个单独的线程,有时它完成而有时却没有,为什么?如何确保线程完成?

java - 易失性布尔与AtomicBoolean

java - Java ThreadFactory问题

java - 试图弄清楚如何仅从用户输入中接受1个字符

java - Windows使用Java或CMD以编程方式更改系统音量

c++ - Tesseract OCR QT错误

c - 试图弄清楚在这种情况下给定的fork()是如何工作的,但我似乎不明白如何实现答案