【问题标题】:ExecutorService using invokeAll and timeout on callables thread not got terminated after timeout exceptionExecutorService 使用 invokeAll 和超时异常后可调用线程上的超时未终止
【发布时间】:2025-11-29 04:25:01
【问题描述】:

我尝试在线程上设置超时,并期望执行程序抛出异常并阻止线程形式运行它终止它,但这不是超时工作发现的情况 但线程完成执行。 如果它通过超时,我如何终止线程? 这是我的测试代码:

class ArithmeticBB implements ArithmeticManagerCallable.ArithmeticAction {
    @Override
    public String arithmetic(String n) {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        String ss  = n+" 2" + " ,Thread ID:" +Thread.currentThread().getId();
        return ss;
    }
}
public class ArithmeticManagerCallable {
    ExecutorService executor = null;
    private List<String> integerList = null;
    private List<String> myResult= Collections.synchronizedList(new ArrayList<>());
    private int threadTimeOutInSec = 180;

    public ArithmeticManagerCallable(List<String> dataFromUser, int poolSize, int threadTimeOutInSec) {
        this.integerList =  dataFromUser;
        executor = Executors.newFixedThreadPool(poolSize);
        this.threadTimeOutInSec = threadTimeOutInSec;
    }
    private void exec(ArithmeticAction arithmeticAction) {
        List<String> tempList = new ArrayList<>();
        for(Iterator<String> iterator = integerList.listIterator(); iterator.hasNext();) {
            tempList.add(arithmeticAction.arithmetic(iterator.next()));
        }
        resultArray.addAll(tempList);
    }
    public List<String> invokerActions(List<ArithmeticAction> actions) throws
            InterruptedException {

        Set<Callable<String>> callables = new HashSet<>();
        for (final ArithmeticAction ac : actions) {
            callables.add(new Callable<String>() {
                public String call() throws Exception{
                    exec(ac);
                    return "done";
                }
            });
        }
        List<Future<String>> futures = executor.invokeAll(callables, this.threadTimeOutInSec, TimeUnit.SECONDS);
        executor.shutdown();
        while (!executor.isTerminated()) {
        }
        return myResult;
    }
    public interface ArithmeticAction {
        String arithmetic(String n);
    }

    public static void main(String[] args) {
        List<ArithmeticManagerCallable.ArithmeticAction> actions = new ArrayList();
        actions.add(new ArithmeticBB());
        List<String> intData = new ArrayList<>();
        intData.add("1");

        ArithmeticManagerCallable arithmeticManagerCallable = new ArithmeticManagerCallable(intData,20,4);

        try {
            List<String> result = arithmeticManagerCallable.invokerActions(actions);
            System.out.println("***********************************************");
            for(String i : result) {
                System.out.println(i);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

【问题讨论】:

    标签: java multithreading timeout threadpool executorservice


    【解决方案1】:

    您的Thread 在超过超时后没有完成它的执行。

    请看这个例子作为参考:

    ExecutorService executorService = Executors.newFixedThreadPool(20);
    
    List<Callable<String>> callableList = new ArrayList<>();
    for (int i = 0; i < 10; i++) {
        final int identifier = i;
        callableList.add(()-> {
            try {
                Thread.sleep(1000 * identifier);
            } catch (InterruptedException e) {
                System.out.println("I'm " + identifier + " and my sleep was interrupted.");
            }
            return identifier + " Hello World";
        });
    }
    
    try {
        List<Future<String>> futureList = executorService.invokeAll(callableList, 5, TimeUnit.SECONDS);
    
        for (Future<String> result : futureList) {
            System.out.println(result.get());
        }
    } catch (InterruptedException | ExecutionException e) {
        System.out.println("Something went wrong while executing. This may help: " + e.getMessage());
    } catch (CancellationException e) {
        System.out.println("Not all Futures could be received.");
    } finally {
        executorService.shutdown();
    }
    
    

    【讨论】:

    • 谢谢,我也知道 executorService 永远不会抛出 TimeoutException ,我怎么知道它是超时的?来自线程的中断异常。睡眠不是来自 executorService 它自己
    • @user63898 invokeAll 不会抛出 TimeoutException。如果您想知道未来是否在完成执行之前超时,那么您必须通过它的第二个 get-Method 直接询问 Future。 -> V get(long timeout, TimeUnit unit)
    • 我喜欢从 TimeoutException 类型中捕获异常,以便我有指标。我注意到这是我做的: executor.submit(new Callable() { public String call() throws Exception{ exec(ac); return "done"; } }).get(this.threadTimeOutInSec, TimeUnit.SECONDS );它确实从 TimeoutException 抛出了正确的异常 invokeAll 和一一提交有什么区别?
    • @user63898 简单地说:这是两种不同的实现方式。 invokeAll 允许您一次提交多个Callables。如果您现在通过invokeAll 执行它们或逐个提交它们,则取决于您作为开发人员。
    • 谢谢我喜欢调用不阻塞的东西