Мы пишем приложение, которое использует пользовательское расширение ThreadPoolExecutor
для обработки связки Runnable
s. При разработке приложения мы столкнулись с OutOfMemoryError
s, которые произошли в наших классах Runnable
. Но вместо того, чтобы называть наш 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);
}
}
}
}
}
Это супер-простой пример, который будет создавать 10k из MyRunnable
с в MyThreadPoolExectuor
, распечатывая некоторые сообщения о статусе как счетчики i ncrease. 16-й ход (число 15, отсчет от 0) будет вызывать OutOfMemoryError
на 200-м приращении. MyThreadPoolExecutor
afterExecute()
напечатает сообщение, если оно получит Throwable
. Когда я запускаю его под Java 6 и Java 7, он никогда не печатает это сообщение.
Как мы можем сделать поручительство на все Throwable
? Мы действительно хотим просто прекратить дело в этот момент.
Update/Edit:
Я обновляю это как кажется, есть некоторая путаница относительно того, что я прошу. Я знаю, что ошибка печатается. Проблема не в том, что ThreadPoolExecutor не печатает OutOfMemoryError
, проблема в том, что указано в заголовке и в вопросе, который я задаю в конце, что afterExecute()
не вызывается для Error
s. Так как OutOfMemoryError
является подклассом Error
, это означает, что когда происходит, у меня есть NO WAY, чтобы остановить код.
Снова прочитайте, что делает код. Это, безусловно, пытается «обработать» ошибку. Фактически он пытается остановить ThreadPoolExecutor
, вызвав на нем shutdownNow()
. Но, поскольку генерируемое 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
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
Работает для меня .. Я вижу ошибку. –