我們正在編寫一個應用程序,它使用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