简体   繁体   English

申请需要很长时间才能终止

[英]Application takes very long to terminate

We have writen a console application (will be used as service) that starts several worker threads for handling requests coming in via mina. 我们编写了一个控制台应用程序(将用作服务),该应用程序启动了多个工作线程来处理通过mina传入的请求。 The application leaves the main loop when a stop signal is received on a specific network port. 当在特定的网络端口上收到停止信号时,应用程序离开主循环。 This is the intended way of stoping the service. 这是停止服务的预期方式。 That works quite ok, but when the stop signal is received the process of the application does not terminate immediatly (takes up to 5 minutes). 效果很好,但是当收到停止信号时,应用程序的处理不会立即终止(最多需要5分钟)。 We verified via log messages that the main function is left quickly and as expected and all threads created by the application are also terminated. 我们通过日志消息验证了主要功能是否按预期快速离开,并且由应用程序创建的所有线程也都终止了。 But the application keeps on running. 但是应用程序继续运行。

The threads still running before leaving the main function are: 离开main函数之前仍在运行的线程是:

Signal Dispatcher (java.lang.Thread)
Finalizer (java.lang.ref.Finalizer$FinalizerThread)
Abandoned connection cleanup thread (com.mysql.jdbc.AbandonedConnectionCleanupThread)
main (java.lang.Thread)
pool-2-thread-1 (java.lang.Thread)
Reference Handler (java.lang.ref.Reference$ReferenceHandler)

We are currently using the following java version: 我们当前正在使用以下Java版本:

java version "1.7.0_80"
Java(TM) SE Runtime Environment (build 1.7.0_80-b15)
Java HotSpot(TM) 64-Bit Server VM (build 24.80-b11, mixed mode)

The operation system is ubuntu 14.04 LTS. 操作系统是ubuntu 14.04 LTS。

I have no clue about this behaviour and i hope for some hints on how to investigate that problem further. 我对此行为一无所知,希望能对如何进一步调查该问题提供一些提示。

Addtional Information 附加信息

I have produced a Full thread dump as suggested. 我已经按照建议进行了全线程转储。 Four threads are waiting: 四个线程正在等待:

"pool-2-thread-1" prio=10 tid=0x00007fd7fc51f000 nid=0x16200 waiting on condition [0x00007fd800318000]
   java.lang.Thread.State: TIMED_WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x00000000cceaf660> (a java.util.concurrent.SynchronousQueue$TransferStack)
    at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:226)
    at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:460)
    at java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:359)
    at java.util.concurrent.SynchronousQueue.poll(SynchronousQueue.java:942)
    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:745)

"Abandoned connection cleanup thread" daemon prio=10 tid=0x00007fd7fc23d800 nid=0x161e2 in Object.wait() [0x00007fd800cbb000]
   java.lang.Thread.State: TIMED_WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x00000000dc2af720> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:135)
    - locked <0x00000000dc2af720> (a java.lang.ref.ReferenceQueue$Lock)
    at com.mysql.jdbc.AbandonedConnectionCleanupThread.run(AbandonedConnectionCleanupThread.java:41)

"Finalizer" daemon prio=10 tid=0x00007fd7fc066000 nid=0x161d6 in Object.wait() [0x00007fd801bd6000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x00000000dc03c060> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:135)
    - locked <0x00000000dc03c060> (a java.lang.ref.ReferenceQueue$Lock)
    at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:151)
    at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:209)

"Reference Handler" daemon prio=10 tid=0x00007fd7fc064000 nid=0x161d5 in Object.wait() [0x00007fd801cd7000]
   java.lang.Thread.State: WAITING (on object monitor)
    at java.lang.Object.wait(Native Method)
    - waiting on <0x00000000dc03c108> (a java.lang.ref.Reference$Lock)
    at java.lang.Object.wait(Object.java:503)
    at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:133)
    - locked <0x00000000dc03c108> (a java.lang.ref.Reference$Lock)

Can someone confirm, that I should investigate towards pool-2-thread-1? 有人可以确认我应该对pool-2-thread-1进行调查吗? I'm unsure how to interpret the result. 我不确定如何解释结果。

Solution In the end a call to acceptor.dispose (MINA) did the trick... 解决方案最后,通过调用acceptor.dispose(MINA)达到了目的。

My guess is you have created an ExecutorService which is running as a non daemon. 我的猜测是您已经创建了一个ExecutorService,它作为非守护程序运行。 This means that if you don't shutdown() this pool it will keep the application running until it stops the thread gracefully (as it has been used for a number of minutes) 这意味着,如果不使用shutdown()这个池,它将使应用程序保持运行状态,直到它优雅地停止线程为止(因为它已经使用了几分钟)

You can create an ExecutorService with daemon threads to make it clear the application doesn't need to wait for this thread pool to stop. 您可以使用守护程序线程创建ExecutorService,以使应用程序无需等待该线程池停止就可以清除。 (Or you can shut it down explicitly) (或者您可以显式关闭它)

String poolName = ....
exec = Executors.newCachedThreadPool(r -> {
    Thread t = new Thread(r, poolName);
    t.setDaemon(true);
    return t;
});

pool-2-thread-1 is nothing that we created intentionally pool-2-thread-1并不是我们故意创建的

This could be created by a library, but it follows the form of an ExecutorService. 这可以由库创建,但是遵循ExecutorService的形式。 Note: it is pool-2.. indicating it is not the first pool the application creates. 注意:它是pool-2..指示它不是应用程序创建的第一个池。

You can force non-system threads to die by using System.exit(0); 您可以使用System.exit(0);强制非系统线程死亡System.exit(0); This is not ideal as the threads might be doing useful work if they were made non-daemon for a good reason, but if the thread is started by a 3rd party library, it might be your simplest option. 这是不理想的,因为如果有充分的理由使线程成为非守护程序,线程可能会做有用​​的工作,但是如果线程是由第3方库启动的,则这可能是您最简单的选择。


Something you could try is tracing where all a Threads are created. 您可以尝试追踪创建所有线程的位置。 One way is to use the debugger to break point the constructor of the ThreadPoolExecutor or any other key method which would show you where the pool is being created. 一种方法是使用调试器来中断ThreadPoolExecutor的构造函数或任何其他可向您显示在何处创建池的关键方法。

Or you can use a memory profiler with allocation tracing. 或者,您可以将内存探查器与分配跟踪一起使用。 Then look at where every Thread object is created. 然后查看每个Thread对象的创建位置。

Another option is to modify the Thread class to include a stack trace of where it was created (or started) You can do this by building you own version and pre-pending it to the boot class path. 另一个选择是修改Thread类,以包含创建(或启动)位置的堆栈跟踪。您可以通过构建自己的版本并将其预先添加到引导类路径中来实现。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM