how to get Future return when cause timeout Exception in java

房东的猫 提交于 2021-02-20 00:42:09

问题


I'm wondering can I get the result when it cause timeout Exception when use Future and ExecutorService, for example, below is my code

package com.example;

import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.junit.Test;

public class FutureTest {
    public static String sayHello() {
        try {
            Thread.sleep(3000);
            return "world";
        } catch (Exception e) {
            return "hello";
        }
    }

    @Test
    public void testTimeoutAndInterrupt() throws Exception {
        ExecutorService executorService = new ThreadPoolExecutor(0, Runtime.getRuntime().availableProcessors() * 2, 0,
            TimeUnit.SECONDS, new LinkedBlockingQueue<>(10), new BasicThreadFactory.Builder().namingPattern(
            "executor-pool-%d").daemon(true).build());

        String processName = UUID.randomUUID().toString();

        Future<String> future = executorService.submit(
            () -> {
                return sayHello();
            }
        );
        try {
            String result = future.get(2, TimeUnit.SECONDS);
            System.out.println("future result:" + result);
        } catch (TimeoutException e) {
            System.out.println("timeout exception");
        } finally {
            future.cancel(true);
            System.out.println("cancel by future");
        }
    }
}

when I use future.get(5, TimeUnit.SECONDS), It's OK to get value "world" as I expect. now I want get the return value is "hello", when I use future.get(2, TimeUnit.SECONDS) .

how can I do this? thanks


回答1:


No, that exception is not thrown inside the execution. Instead a InterruptedException is thrown. (Try a System.out.println there).

The flow of control:

    1. Timeout happens in the execution
    1. The thread is interrupted
  • 3a. A TimeoutException thrown
  • 3b. The FutureTask gets an InterruptedException

As 3a and 3b happen in two threads (asynchroneously) the order could be 3b;3a. However 3a;3b seems the natural order.

So do:

    String result;
    try {
        result = future.get(2, TimeUnit.SECONDS);
        System.out.println("future result:" + result);
    } catch (TimeoutException e) {
        System.out.println("timeout exception");
        result = "hello";
    } finally {

Notice: I think the FutureTask thread is not guaranteed to have shutdown (as there might not have been a catch, and even then after the catch the code continues).

Using catch InterruptedException to somewhere deposit a result, will fail, as at the moment of catching the TimeoutException the FutureTask still can have no InterruptedException.

This is also a pitfall when storing a progress in every loop step. After catching the timeout the progress might still be updated.



来源:https://stackoverflow.com/questions/48109628/how-to-get-future-return-when-cause-timeout-exception-in-java

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!