【问题标题】:Futures, TimeoutException, and Callables with finally blocks带有 finally 块的 Futures、TimeoutException 和 Callables
【发布时间】:2012-12-29 16:27:54
【问题描述】:

如果通过 future.get(timeout, TimeUnit.SECONDS) 取消 Callable,是否会调用带有线程的 finally 块?

class MyCallable implements Callable<Future<?>>{
    public Future<?> call(){
        Connection conn = pool.getConnection();
        try {
            ... 
        } catch(CatchExceptions ce){
        } finally {
            conn.close();
        }
    } 
}

... 

future.get(executionTimeoutSeconds, TimeUnit.SECONDS);

我知道 finally 总是会被调用,但我猜我错过了一些关于线程如何被中断的东西。这是我运行的一个测试,它没有显示我的 finally 块被解雇了。

@Test
public void testFuture(){
    ExecutorService pool =  Executors.newFixedThreadPool(1);
    try {
        pool.submit(new TestCallable()).get(1, TimeUnit.SECONDS);
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (ExecutionException e) {
        e.printStackTrace();
    } catch (TimeoutException e) {
        e.printStackTrace();
    }
}

class TestCallable implements Callable<Void> {
    @Override
    public Void call() throws Exception {
        try{
        while(true){
            Thread.sleep(3000);
            break;
        }
        } catch (Exception e){
            System.out.println("EXCEPTION CAUGHT!");
            throw e;
        } finally {
            System.out.println("FINALLY BLOCK RAN!");
        }
    }

}

看起来如果我添加 awaitTermination 它会运行。 此测试通过...

public void testFuture(){
    ExecutorService pool =  Executors.newFixedThreadPool(1);
    try {
        pool.submit(new TestCallable()).get(1, TimeUnit.SECONDS);
    } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (ExecutionException e) {
        e.printStackTrace();
    } catch (TimeoutException e) {
        e.printStackTrace();
    }
    try {
        pool.awaitTermination(10, TimeUnit.SECONDS);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

【问题讨论】:

    标签: java concurrency future callable timeoutexception


    【解决方案1】:

    future.get(...) 不会取消线程。它只等待线程完成,如果等待超时则抛出TimeoutException

    future.cancel(true) 导致线程中断。这可能会也可能不会阻止您的线程处理。这取决于您的 try ... 部分内部发生的情况。例如Thread.sleep(...)Object.wait(...)等方法在线程中断时抛出InterruptedException。否则你需要检查线程中断标志

    if (Thread.currentThread().isInterrupted()) {
        // maybe stop the thread or whatever you want
        return;
    }
    

    如果输入了try 块,则总是 调用finally 块(无论是否中断),除非出现某种JVM 故障和崩溃。我怀疑你的线程根本没有被中断,所以继续运行。

    【讨论】:

    • 只是一点评论:如果 try 块开始执行,总是调用 finally 块。如果线程没有进入 try 块并且之前被终止,那么 finally 当然不会被调用。
    猜你喜欢
    • 1970-01-01
    • 2018-11-07
    • 1970-01-01
    • 2016-10-07
    • 2023-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-25
    相关资源
    最近更新 更多