后端webapp部署在Tomcat 6 servlet容器上。在webapp中,启动了几个监视线程。问题在于关机。
目前我的线程实现如下。当servlet被指示关闭(shutdown.sh)时,它确实完成了一个干净的关闭并且因为这个线程而没有挂起 - 为什么?
class Updater extends Thread {
volatile boolean interrupted = false;
@Override
public void run() {
Integer lastUpdateLogId = CommonBeanFactory.getXXX()
.getLastUpdateLogRecordKey(MLConstants.SMART_DB_NAME);
List<UpdateLog> updateLogRecords;
while (!interrupted) {
boolean isConfigurationUpdateRequested = false;
try {
TimeUnit.SECONDS.sleep(5);
} catch (InterruptedException e) {
setInterrupted(true);
}
updateLogRecords = CommonBeanFactory.getXXX()
.getLastFactsUpdateLogRecords(MLConstants.XXXX, lastUpdateLogId);
for(UpdateLog updateLog : updateLogRecords) {
if (updateLog.getTable_name().equals(MLConstants.CONFIG_RELOAD)) {
isConfigurationUpdateRequested = true;
}
lastUpdateLogId = updateLog.getObjectKey();
}
if (isConfigurationUpdateRequested) {
Configuration.getInstance().loadConfiguration();
}
}
}
public boolean getInterrupted() {
return interrupted;
}
public void setInterrupted(boolean interrupted) {
this.interrupted = interrupted;
}
}
答案 0 :(得分:6)
我想我还不能回复答案。艾迪的回答并不完全正确。
我发现了这个问题,因为我试图找出为什么我的webapp没有正常关闭;当我运行shutdown时,我的线程不会被杀死。*。事实上,它会阻止一些线程,但最终只是处于某种不稳定状态。实际上,我的班级几乎就是这个班级。
在前台Tomcat窗口(在Windows上)键入Ctrl + C会停止所有操作,但是使用Tomcat附带的init脚本则不会。不幸的是,我还没弄明白为什么......
编辑:我明白了。我的大多数监视线程都是在ServletContextListener中启动的,但是当该上下文被“销毁”时,子线程不会被通知。我通过简单地将所有子线程保留在List中并循环遍历,在contextDestroyed()方法中的每个上调用Thread.interrupt()来修复它。它与Eddie关于servlet destroy()方法的内容几乎相同。
但是,当你运行shutdown时,JVM会被立即关闭是不正确的。{sh | bat}。它更像是脚本向Tomcat组件发送关闭请求。您可以接收这些关闭消息并将它们传递给您自己的对象。
答案 1 :(得分:3)
Servlet在被指示关闭时收到生命周期事件。您可以使用此事件来停止监视线程。也就是说,当servlet启动时,会调用其init()
方法。停止时,将调用其destroy()
方法。
覆盖servlet中的destroy()
方法并在那里停止线程。
当您致电shutdown.sh
时,整个JVM都会关闭。因为JVM停止,所有线程(无论其状态如何)如果仍在运行则被强制停止。这是调用System.exit(0);