我正在开发一个使用Tomcat与Raspberry PI进行通信的应用程序。 GUI以html完成,并且使用websockets实现这两者之间的通信。到现在为止还挺好。
我想在应用程序首次运行时启动一个线程,以便启动一系列任务。这是我已经完成的测试:
public class ContexService implements ServletContextListener {
Thread thread;
ExecutorService executorService;
// ServiceManager serviceManager;
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("-------------> CONTEXT INITIALIZED <-------------");
executorService = Executors.newSingleThreadExecutor();
executorService.submit(new Runnable() {
@Override
public void run() {
Test p = new Test();
int count = 0;
while (count < 20) {
p.imprimir(count);
count++;
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
System.out.println("error - > " + ex.getMessage());
}
}
}});
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("-------------> CONTEXT DESTROYED <-------------");
if(executorService!=null)
{
if(!executorService.isShutdown())
{
try {
executorService.shutdown();
executorService.awaitTermination(3, TimeUnit.SECONDS);
if(!executorService.isTerminated())
{
executorService.shutdownNow();
}
} catch (InterruptedException ex) {
Logger.getLogger(ContexService.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
}
我运行它并且它有效。我的问题是,每次按&#34;播放&#34;在Netbeans上,它再次启动所有内容(这就是我想要的)但是使用ExecutorService重新启动的线程是活动的。我附上了tomcat的控制台输出,所以你明白了我的意思:
-------------> CONTEXT DESTROYED <-------------
05-May-2016 15:19:41.668 INFO [http-apr-8080-exec-66] org.apache.catalina.startup.HostConfig.undeploy Repliegue (undeploy) de la aplicación web que tiene como trayectoria de contexto /safemo
05-May-2016 15:19:41.694 INFO [http-apr-8080-exec-65] org.apache.catalina.startup.HostConfig.deployDescriptor Desplieque del descriptor de configuración C:\apache-tomcat-8.0.33\conf\Catalina\localhost\safemo.xml
05-May-2016 15:19:42.268 INFO [http-apr-8080-exec-65] org.apache.catalina.startup.HostConfig.deployDescriptor Deployment of configuration descriptor C:\apache-tomcat-8.0.33\conf\Catalina\localhost\safemo.xml has finished in 574 ms
05-May-2016 15:19:42.273 INFO [http-apr-8080-exec-69] org.apache.catalina.util.LifecycleBase.start The start() method was called on component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/safemo]] after start() had already been called. The second call will be ignored.
-------------> CONTEXT INITIALIZED <-------------
15:19:42.446 [pool-4-thread-1] DEBUG sal.Test - 0 --> TEST <--Thu May 05 15:19:42 CEST 2016
15:19:43.455 [pool-4-thread-1] DEBUG sal.Test - 1 --> TEST <--Thu May 05 15:19:42 CEST 2016
15:19:44.456 [pool-4-thread-1] DEBUG sal.Test - 2 --> TEST <--Thu May 05 15:19:42 CEST 2016
15:19:45.456 [pool-4-thread-1] DEBUG sal.Test - 3 --> TEST <--Thu May 05 15:19:42 CEST 2016
15:19:46.456 [pool-4-thread-1] DEBUG sal.Test - 4 --> TEST <--Thu May 05 15:19:42 CEST 2016
-------------> CONTEXT DESTROYED <-------------
15:19:47.456 [pool-4-thread-1] DEBUG sal.Test - 5 --> TEST <--Thu May 05 15:19:42 CEST 2016
15:19:48.456 [pool-4-thread-1] DEBUG sal.Test - 6 --> TEST <--Thu May 05 15:19:42 CEST 2016
15:19:49.457 [pool-4-thread-1] DEBUG sal.Test - 7 --> TEST <--Thu May 05 15:19:42 CEST 2016
error - > sleep interrupted
15:19:49.484 [pool-4-thread-1] DEBUG sal.Test - 8 --> TEST <--Thu May 05 15:19:42 CEST 2016
05-May-2016 15:19:49.487 WARNING [http-apr-8080-exec-77] org.apache.catalina.loader.WebappClassLoaderBase.clearReferencesThreads The web application [safemo] appears to have started a thread named [pool-4-thread-1] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
java.lang.Thread.sleep(Native Method)
sal.ContexService$1.run(ContexService.java:42)
java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
java.util.concurrent.FutureTask.run(FutureTask.java:266)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
java.lang.Thread.run(Thread.java:745)
05-May-2016 15:19:49.991 INFO [http-apr-8080-exec-77] org.apache.catalina.startup.HostConfig.undeploy Repliegue (undeploy) de la aplicación web que tiene como trayectoria de contexto /safemo
05-May-2016 15:19:50.034 INFO [http-apr-8080-exec-63] org.apache.catalina.startup.HostConfig.deployDescriptor Desplieque del descriptor de configuración C:\apache-tomcat-8.0.33\conf\Catalina\localhost\safemo.xml
15:19:50.484 [pool-4-thread-1] DEBUG sal.Test - 9 --> TEST <--Thu May 05 15:19:42 CEST 2016
05-May-2016 15:19:50.682 INFO [http-apr-8080-exec-63] org.apache.catalina.startup.HostConfig.deployDescriptor Deployment of configuration descriptor C:\apache-tomcat-8.0.33\conf\Catalina\localhost\safemo.xml has finished in 648 ms
05-May-2016 15:19:50.686 INFO [http-apr-8080-exec-70] org.apache.catalina.util.LifecycleBase.start The start() method was called on component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/safemo]] after start() had already been called. The second call will be ignored.
-------------> CONTEXT INITIALIZED <-------------
15:19:50.818 [pool-5-thread-1] DEBUG sal.Test - 0 --> TEST <--Thu May 05 15:19:50 CEST 2016
15:19:51.484 [pool-4-thread-1] DEBUG sal.Test - 10 --> TEST <--Thu May 05 15:19:42 CEST 2016
15:19:51.824 [pool-5-thread-1] DEBUG sal.Test - 1 --> TEST <--Thu May 05 15:19:50 CEST 2016
15:19:52.485 [pool-4-thread-1] DEBUG sal.Test - 11 --> TEST <--Thu May 05 15:19:42 CEST 2016
15:19:52.825 [pool-5-thread-1] DEBUG sal.Test - 2 --> TEST <--Thu May 05 15:19:50 CEST 2016
15:19:53.485 [pool-4-thread-1] DEBUG sal.Test - 12 --> TEST <--Thu May 05 15:19:42 CEST 2016
15:19:53.825 [pool-5-thread-1] DEBUG sal.Test - 3 --> TEST <--Thu May 05 15:19:50 CEST 2016
15:19:54.485 [pool-4-thread-1] DEBUG sal.Test - 13 --> TEST <--Thu May 05 15:19:42 CEST 2016
15:19:54.825 [pool-5-thread-1] DEBUG sal.Test - 4 --> TEST <--Thu May 05 15:19:50 CEST 2016
15:19:55.486 [pool-4-thread-1] DEBUG sal.Test - 14 --> TEST <--Thu May 05 15:19:42 CEST 2016
15:19:55.826 [pool-5-thread-1] DEBUG sal.Test - 5 --> TEST <--Thu May 05 15:19:50 CEST 2016
15:19:56.486 [pool-4-thread-1] DEBUG sal.Test - 15 --> TEST <--Thu May 05 15:19:42 CEST 2016
15:19:56.826 [pool-5-thread-1] DEBUG sal.Test - 6 --> TEST <--Thu May 05 15:19:50 CEST 2016
15:19:57.486 [pool-4-thread-1] DEBUG sal.Test - 16 --> TEST <--Thu May 05 15:19:42 CEST 2016
15:19:57.826 [pool-5-thread-1] DEBUG sal.Test - 7 --> TEST <--Thu May 05 15:19:50 CEST 2016
15:19:58.486 [pool-4-thread-1] DEBUG sal.Test - 17 --> TEST <--Thu May 05 15:19:42 CEST 2016
15:19:58.826 [pool-5-thread-1] DEBUG sal.Test - 8 --> TEST <--Thu May 05 15:19:50 CEST 2016
15:19:59.486 [pool-4-thread-1] DEBUG sal.Test - 18 --> TEST <--Thu May 05 15:19:42 CEST 2016
15:19:59.826 [pool-5-thread-1] DEBUG sal.Test - 9 --> TEST <--Thu May 05 15:19:50 CEST 2016
15:20:00.486 [pool-4-thread-1] DEBUG sal.Test - 19 --> TEST <--Thu May 05 15:19:42 CEST 2016
15:20:00.827 [pool-5-thread-1] DEBUG sal.Test - 10 --> TEST <--Thu May 05 15:19:50 CEST 2016
15:20:01.827 [pool-5-thread-1] DEBUG sal.Test - 11 --> TEST <--Thu May 05 15:19:50 CEST 2016
15:20:02.827 [pool-5-thread-1] DEBUG sal.Test - 12 --> TEST <--Thu May 05 15:19:50 CEST 2016
15:20:03.827 [pool-5-thread-1] DEBUG sal.Test - 13 --> TEST <--Thu May 05 15:19:50 CEST 2016
15:20:04.827 [pool-5-thread-1] DEBUG sal.Test - 14 --> TEST <--Thu May 05 15:19:50 CEST 2016
15:20:05.827 [pool-5-thread-1] DEBUG sal.Test - 15 --> TEST <--Thu May 05 15:19:50 CEST 2016
15:20:06.827 [pool-5-thread-1] DEBUG sal.Test - 16 --> TEST <--Thu May 05 15:19:50 CEST 2016
15:20:07.828 [pool-5-thread-1] DEBUG sal.Test - 17 --> TEST <--Thu May 05 15:19:50 CEST 2016
15:20:08.828 [pool-5-thread-1] DEBUG sal.Test - 18 --> TEST <--Thu May 05 15:19:50 CEST 2016
15:20:09.828 [pool-5-thread-1] DEBUG sal.Test - 19 --> TEST <--Thu May 05 15:19:50 CEST 2016
我启动应用程序并使用pool4-thread 1开始打印测试。我重新启动它并且线程仍在工作,并启动一个新线程(pool5-thread1)。
如果我执行&#34; executorService.shutDown&#34;为什么线程不会停止? on contextDestroyed?
谢谢!
答案 0 :(得分:1)
在你的问题中似乎有两个谜团需要解决:
MYSTERY1:为什么不停止? 检查你的run方法:它将循环20次(从0到19)并在每次循环时等待1秒。所以,至少在两十秒后才能完成。
您的关机只等待三秒钟。到那时,你的工作还没有完成。您可以尝试替换此行:
executorService.awaitTermination(3, TimeUnit.SECONDS);
用这个:
executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
这样,它会等到你的任务真正完成。注意:即使您没有等待并且从get get开始调用shutdownNow,这也无效。代码的那一部分应该被重构,这样你就不会简单地循环20次,而是检查线程在循环时是否被中断,以便它可以干净地完成(短路)它的处理。尝试更改此行:
while (count<20) {
这一个:
while (count<20 && !Thread.currentThread().isInterrupted()) {
此解决方案应该有助于解释我上面所说的内容: Why ExecutorService.shutdownNow method can't stop the thread 另外值得阅读shutdownNow:http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ExecutorService.html
的文档除了尽力尝试停止处理主动执行任务之外,没有任何保证。例如,典型的实现将通过Thread.interrupt()取消,因此任何无法响应中断的任务都可能永远不会终止。
MYSTERY2:为什么Netbeans同时运行2个线程? 这可能是因为您正在运行的线程从未停止过处理,并且没有处理中断请求。所以,这是预期的,你的程序将继续运行直到它完成(java试图告诉你的代码停止但你的代码当前没有收听这些消息)。所以,是的,当你再次启动程序时,两个线程都在同一时间运行(前一个运行仍在运行,而你正在启动另一个)。一旦一个线程到达第20个循环(index = 19),taht线程就会被清除,并且JVM有望最终关闭。也就是说,除非您遇到运行JVM的NetBeans错误: https://netbeans.org/bugzilla/show_bug.cgi?id=232322
答案 1 :(得分:1)
如果我执行&#34; executorService.shutDown&#34;为什么线程不会停止? on contextDestroyed?
根据Oracle文档页面的建议关闭ExecutorService。
你的方法应该改变
val result = (for (v<-option if condition) yield valueToResult(v)).getOrElse(defaultResult)
public void contextDestroyed(ServletContextEvent sce) {
executorService.shutdown(); // Disable new tasks from being submitted
try {
// Wait a while for existing tasks to terminate
if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
executorService.shutdownNow(); // Cancel currently executing tasks
// Wait a while for tasks to respond to being cancelled
if (!executorService.awaitTermination(60, TimeUnit.SECONDS))
System.err.println("executorService did not terminate");
}
} catch (InterruptedException ie) {
// (Re-)Cancel if current thread also interrupted
executorService.shutdownNow();
// Preserve interrupt status
Thread.currentThread().interrupt();
}
}
启动有序关闭,其中先前提交的任务已执行,但不会接受任何新任务。
shutdown():
尝试停止所有正在执行的任务,停止等待任务的处理,并返回等待执行的任务列表。
如果关闭shutdownNow():
这
ExecutorService
要
if (!executorService.awaitTermination(60, TimeUnit.SECONDS))
如果您按照上述代码正确处理关闭,则可能无法在多个while (!executorService.awaitTermination(60, TimeUnit.SECONDS))
Thread.sleep(60000);
池中遇到第二个问题。