为什么这个OutOfMemoryError在被Future抛出时不显示?

时间:2013-04-15 03:40:53

标签: java concurrency out-of-memory

一个简单的场景:

private static final ExecutorService executor =
        Executors.newCachedThreadPool();

public static void main(String... args) throws InterruptedException, ExecutionException {
    Future<byte[]> f = null;
    for (int i = 0; i < 10; i++) {
        f = executor.submit(new Callable<byte[]>(){
            @Override
            public byte[] call() {
                System.out.println("Starting task.");
                try {
                    return new byte[1500 * 1024 * 1024];    // 1500 mb
                }
                finally {
                    System.out.println("Task complete.");
                }
            }
        });
    }
//  System.out.println(f.get().length);
}

当我运行上面的代码时,它(据称)运行没有错误。

(奇怪的是,当我在NetBeans中分析此代码时,会抛出 OutOfMemoryError ,但在我正常运行时却不会抛出。)

全部10个“任务完成。”消息立即显示,在一个太短的时间范围内,实际分配的字节数组太短。

当我取消注释最后一行时,抛出 ExecutionException

我知道代码示例有点荒谬...... 但是为什么没有异常被抛出,我怎么能让 OutOfMemoryError 出现呢?我必须抓住它吗?这是安全的操作吗?

2 个答案:

答案 0 :(得分:3)

你不应该抓住Errors - 他们的目的是吵闹你的程序。如果a,您应该只捕获Exception。你正在记录它/重新投掷它或b。你正在处理它;你没办法处理OutOfMemoryError,所以让你的程序崩溃就像它应该的那样。

“任务完成”在分配Future个对象时显示,而不是在他们完成工作时显示 - 您需要在每个Future上调用f.get()以确保它已完成分配它的字节数组。当您对其进行性能分析时,程序运行速度较慢,这允许更多Futures在Main方法终止之前分配其字节数组,这反过来又允许它们耗尽所有堆空间。

f更改为期货的ArrayList(以及f = executor.submitf.add(executor.submit)),然后迭代它并在其所有期货上调用.get()。这应该在不使用探查器的情况下触发OutOfMemoryError。

答案 1 :(得分:0)

主线程不会自动识别线程引发的异常抛出。 使用了以前的run方法,它不会抛出异常而你被迫使用uncaughtexceptionhandler。

引入了JDK1.5期货和期货。 callables的调用方法抛出异常并返回值。现在要捕获call方法抛出的异常,你需要调用future.get()。

所以你的代码工作正常。