2

一个简单的场景:

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出现?我必须抓住它吗?那会是安全的操作吗?

4

2 回答 2

3

你不应该抓住Errors- 他们打算吵闹地让你的程序崩溃。你应该只捕获一个Exceptionif a。你正在记录它/重新扔它或b。你正在处理它;你没有办法处理一个OutOfMemoryError,所以让它像它应该的那样让你的程序崩溃。

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

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

于 2013-04-15T03:47:20.883 回答
0

主线程不会自动意识到线程抛出的异常。使用了以前的运行方法,它不会引发异常,您被迫使用 uncaughtexceptionhandler。

JDK1.5 及以后的期货和可调用对象被引入。可调用对象的调用方法会引发异常并返回值。现在要捕获调用方法抛出的异常,您需要调用future.get()。

所以你的代码运行良好。

于 2013-04-15T03:53:16.460 回答