我们正在编写一个应用程序,它使用ThreadPoolExecutor
的自定义扩展来处理一堆Runnable
s。在开发应用程序时,我们遇到了在Runnable
类中发生的OutOfMemoryError
。但是,与我们预期的afterExecute()
不同,ThreadPoolExecutor
只是继续运输。ThreadPoolExecutor忽略错误(OutOfMemoryError)
我已经将代码削减到一个小的,可重复的应用程序。
ThreadPoolTest.java:
package org.codechimp.threadpool;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ThreadPoolTest {
/**
* @param args
*/
public static void main(String[] args) {
LinkedBlockingQueue<Runnable> threadQueue = new LinkedBlockingQueue<Runnable>();
ThreadPoolExecutor executor = new MyThreadPoolExecutor(10, Integer.MAX_VALUE, 2000, TimeUnit.MILLISECONDS, threadQueue);
// Create a bunch of Runnables now...
for (int i = 0; i < 10000; i++) {
executor.execute(new MyRunnable(i));
if (i % 100 == 0) {
System.out.println("Queued " + i + " Runnables");
}
if (i % 1000 == 0) {
try {
Thread.sleep(1);
} catch (InterruptedException ignored) { }
}
}
System.out.println("Done queing the Runnables.");
while (!executor.isTerminated() && !executor.isTerminating() && executor.getQueue().size() > 0) {
System.out.println(executor.getQueue().size() + " Runnables in the queue.");
try {
Thread.sleep(1000);
} catch (InterruptedException ignored) { }
}
System.out.println("Runnable queue has stopped processing.");
executor.shutdown();
try {
executor.awaitTermination(10, TimeUnit.MINUTES);
} catch (InterruptedException ignored) { }
System.out.println("Shutdown completed...exiting");
}
}
MyThreadPoolExecutor.java:
package org.codechimp.threadpool;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class MyThreadPoolExecutor extends ThreadPoolExecutor {
public MyThreadPoolExecutor(int corePoolSize, int maximumPoolSize,
long keepAliveTime, TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
}
public MyThreadPoolExecutor(int corePoolSize, int maximumPoolSize,
long keepAliveTime, TimeUnit unit,
BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, handler);
}
public MyThreadPoolExecutor(int corePoolSize, int maximumPoolSize,
long keepAliveTime, TimeUnit unit,
BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory);
}
public MyThreadPoolExecutor(int corePoolSize, int maximumPoolSize,
long keepAliveTime, TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
}
@Override
protected void afterExecute(Runnable r, Throwable t) {
if (t != null) {
System.out.println("We got an error: " + t);
int remaining = this.shutdownNow().size();
System.out.println(remaining + " Runnables left in the queue");
}
}
}
MyRunnable.java
package org.codechimp.threadpool;
import org.apache.commons.lang.math.RandomUtils;
public class MyRunnable implements Runnable {
private int runnableNumber;
private int counter = 0;
public MyRunnable(int number) {
this.runnableNumber = number;
}
/**
* Simple runnable that generates an OutOfMemoryError after the 1000th loop
*/
public void run() {
while (counter < 1000) {
counter++;
if (counter % 100 == 0) {
System.out.println("\tRunnable " + this.runnableNumber + " reached " + this.counter + ".");
}
if (this.runnableNumber == 15 && this.counter % 200 == 0) {
throw new OutOfMemoryError("This is a test!");
}
int wait = RandomUtils.nextInt(100);
if (wait > 0) {
try {
//System.out.println("\tRunnable " + this.runnableNumber + " waiting " + wait + ".");
Thread.sleep(wait);
} catch (InterruptedException e) {
throw new RuntimeException("Thread.sleep() failed", e);
}
}
}
}
}
这是一个超级简单的例子,将创造MyRunnable
S的10K进入MyThreadPoolExectuor
,打印出一些状态信息作为计数器i现象越来越多。第16次可运行(数字15,从0开始计数)将在第200次增量时抛出OutOfMemoryError
。 MyThreadPoolExecutor
的afterExecute()
将打印一条消息,如果它获得Throwable
。当我在Java 6和Java 7下运行它时,它从不打印此消息。
我们如何让应用程序保全在所有Throwable
s?我们真的想在这一点上终止事情。
更新/编辑:
我更新这是似乎有一些混乱,以什么我问。 我知道错误被打印出来。问题不在于ThreadPoolExecutor未打印OutOfMemoryError
,问题是,正如标题和我在最后询问的问题中所述,afterExecute()
未被调用Error
s。由于OutOfMemoryError
是Error
的子类,这意味着当发生一个我有没有方法停止代码。
再次,请阅读代码试图做的事情。当然,它试图“处理”错误。它实际上试图通过呼吁shutdownNow()
停止ThreadPoolExecutor
。但是,由于生成的Error
以某种方式被抑制,所以该位代码未被执行。结果,应用程序只是一直在徘徊,而忽略了它将OOME喷到整个地方的事实。
同样,问题:
How do I detect a Runnable has recieved an Error (OutOfMemoryError or other) and terminate the ThreadPoolExecutor so the app will simply stop in it's tracks?
我没有运行在Java中jdk1.7.0_40你的代码,并得到这个错误消息 >我们得到了一个错误:java.lang.OutOfMemoryError:这是一个测试! – Maas 2014-09-05 14:26:39
http://stackoverflow.com/questions/511013/how-to-handle-outofmemoryerror-in-java,http://stackoverflow.com/questions/37335/how-to-deal-with-java-lang-outofmemoryerror -java堆空间误差-64MB堆。底线:你不应该处理OutOfMemoryError,你应该防止它发生 – jny 2014-09-05 14:31:53
适用于我..我看到错误。 – 2014-09-05 14:42:44