2017-08-08 66 views
1

我有一个在Ubuntu 16.04 LTS上运行的Java应用程序。关闭线程在执行端点呼叫时消失

当应用程序接收到关闭信号,停止序列像这样运行:

Runtime.getRuntime().addShutdownHook(new Thread() { 
     @Override 
     public void run() { 
      shutdown(); 
     } 
    }); 

这工作得很好,但只要我尝试调用外部REST端点(我用的改造,其中Rx Observable)线程完全消失,端点永远不会被调用,并且连续的命令不再被执行。

  • 我首先想到Observables会是问题,并使用改造Call来代替。同样的问题。
  • 然后我尝试进行同步调用,而不是调用端点异步。同样的问题。
  • 关机时间不是问题。我明确地给了30秒。

我认为这与线程有关,当一个库在关闭时创建额外的线程时,JVM似乎会杀死所有内容。

任何人都可以摆脱光线或建议我可以尝试什么,请。

-

额外信息:

我需要执行长期运行的清理。问题是我无法确定关闭信号是如何看起来像什么时候发生的,因为JVM运行在一个Docker容器中,该容器在docker stop(当主机停止时)首先发送SIGTERM,然后在超时之后(我可以设置,目前60秒)SIGKILL。容器中的JVM运行socket.io,可以连接数千个客户端。我希望使用60秒向每个客户端发送good-bye,并干净地断开这些连接,并从负载均衡器注销服务器。所以在清理过程中有很多潜在的阻塞操作。

如果你的Java认为,清理总是短暂的,那么Java是错误的:(

+2

关闭挂钩应尽快退出,并且肯定不参与网络操作。看到Javadoc。 – EJP

回答

2

当因此,一旦关闭JVM你的情况提出了中断的标志。当你调用任何阻塞操作,一个马上会如果你必须在你的应用程序终止时执行进一步的,可能持久的代码,那么关闭钩子不是一个好办法,它可以关闭开放的资源,而不是创建新的。

由于您没有提供关于您的代码的进一步信息,我不能给出一个确切的建议,但总体思路是让主线程在应用程序运行时等待,并让那个人执行清理工作。在这种情况下,您需要关闭信号而不是系统关闭信号,因此应用程序可以继续正常运行。

如果是出于某种原因太复杂,你可以尝试做这样的事情,以清除在您关闭挂钩的开始中断的标志:

try { 
    Thread.sleep(1); 
} catch (InterruptedException e) { 
} 

然而,这是违反规定的,以及那些存在因为某种原因。即操作系统可能会认为你的程序挂起,如果它不能对kill信号作出足够快的反应,并以更糟糕的方式终止它。

+0

这回答我的问题。如果您有更多的想法,我仍然在上面添加额外的信息。但是我猜中断线程是我能做的唯一事情,并且它相当安全,因为“OS是Docker”,如果我的中断线程没有按时退出,它将发送'SIGKILL'。 –