Java Servlet“已启动一个线程但未能停止它”-Tomcat 中的内存泄漏
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25126980/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Servlet "has started a thread but failed to stop it" - memory leak in Tomcat
提问by user3876178
Apache Tomcat says many times:
Apache Tomcat 多次说:
The web application [/MyServlet] appears to have started a thread named [pool-61-thread-2] but has failed to stop it. This is very likely to create a memory leak.
Web 应用程序 [/MyServlet] 似乎启动了一个名为 [pool-61-thread-2] 的线程,但未能将其停止。这很可能造成内存泄漏。
Is this dangerous? The servlet should be able to handle 10.000requests/day. How to close the threads when they have finished?
这很危险吗?servlet 应该能够处理 10.000 个请求/天。线程完成后如何关闭?
class Worker {
private final CountDownLatch startSignal;
private final CountDownLatch doneSignal;
private final int threadNumber;
Worker(
CountDownLatch startSignal,
CountDownLatch doneSignal,
int threadNumber
){
this.startSignal = startSignal;
this.doneSignal = doneSignal;
this.threadNumber = threadNumber;
}
public String[][] getSomeStrArrArr() {
String[][] isRs = new String[8][20];
String[][] inRs = new String[8][20];
String[][] iwRs = new String[8][20];
try {
startSignal.await();
if (threadNumber == 1) {
// get String[][] result for thread number 1
isRs = getIS(erg1, erg2, request);
}
if (threadNumber == 2) {
// get String[][] result for thread number 2
inRs = getIN(search_plz, request);
}
if (threadNumber == 3) {
// get String[][] result for thread number 3
iwRs = getIW(erg1, erg2, request);
}
doneSignal.countDown();
} catch (InterruptedException ex) {
System.out.println(
"Thread number "+threadNumber+" has been interrupted."
);
}
if (threadNumber == 1) {
return isRs;
}
if (threadNumber == 2) {
return inRs;
}
if (threadNumber == 3) {
return iwRs;
}
return null;
}
public Callable<String[][]> getSomeCallableStrArrArr(){
return new Callable<String[][]>() {
public String[][] call() throws Exception {
return getSomeStrArrArr();
}
};
}
}
ExecutorService pool = Executors.newFixedThreadPool(3);
Set<Future<String[][]>> set = new HashSet<Future<String[][]>>();
CountDownLatch startSignal = new CountDownLatch(1);
CountDownLatch doneSignal = new CountDownLatch(3);
for (int i=1;i<=3;i++) {
Worker worker = new Worker(startSignal,doneSignal,i);
Callable<String[][]> callable =
worker.getSomeCallableStrArrArr();
Future<String[][]> future = pool.submit(callable);
set.add(future);
}
startSignal.countDown();
try {
doneSignal.await();
采纳答案by Nathan Hughes
Yes, it's a problem. If your code starts non-daemon threads then those threads will continue working until they exit their run method. Even if everything else finishes, the old JVM will hang around while those threads continue on. If you start up a new instance then you can have a situation where the old threads are still working alongside the ones created by the new instance.
是的,这是个问题。如果您的代码启动非守护线程,那么这些线程将继续工作,直到它们退出它们的 run 方法。即使其他一切都完成了,旧的 JVM 仍会在这些线程继续运行时闲逛。如果您启动一个新实例,那么您可能会遇到旧线程仍在与新实例创建的线程一起工作的情况。
The tasks need to be designed so that they will be responsive to interruption (as opposed to eating the exception and going on, which is what your example shows). That means checking the interrupted flag on the current thread, and catching InterruptedException in a helpful way that allows the task to break its work off and also resets the interrupted flag if needed. ExecutorService implementations have a shutdownNow method that will interrupt the current tasks.
需要设计任务,以便它们能够响应中断(而不是吃掉异常并继续,这就是您的示例所示)。这意味着检查当前线程上的中断标志,并以一种有用的方式捕获 InterruptedException 以允许任务中断其工作并在需要时重置中断标志。ExecutorService 实现有一个 shutdownNow 方法,它将中断当前任务。
Here's an example of how to stop a thread using interruption.
Make sure the executor gets shut down, you can handle this in a ServletContextListener.
确保 executor 被关闭,你可以在 ServletContextListener 中处理这个。