繁体   English   中英

如何使用 executor.execute 和 future.get() 结束任务(使线程超时)(通过上升中断)而不阻塞主线程

[英]How to end a task(timeout a thread) (by rising interrupt) using executor.execute and future.get() without blocking the main thread

我尝试在执行器服务中使用未来,它可以在不阻塞主线程的情况下工作。 然而,这最终会创建双倍数量的线程,这是不可取的。 在下面的代码中,我能够在没有阻塞的情况下使用 future.get() 但我必须创建双倍数量的线程

 for (int i : array) {
                executor.execute(() -> {
                    Future f = new FutureTask(() -> {
                        Goring goring = new Goring();
    
                        goring.goring(i);
    
                    }, null);
                    Thread thread = new Thread((Runnable) f);
                    thread.start();
    
                    try {
                        f.get(1, TimeUnit.NANOSECONDS);
                    } catch (InterruptedException | ExecutionException | TimeoutException|RuntimeException e) {
                        // TODO Auto-generated catch block
                        // System.out.println(e.getMessage());
                        e.printStackTrace();
                        f.cancel(true);
                    }
    
                });
            }
            
    
        executor.shutdown();
    
        }

通常我会推荐使用ExecutorService.invokeAll ,它允许提交任意数量的超时任务,并在超时到期时取消任何尚未完成的任务。

但是您在评论中声明您希望能够在较小的并行组中提交任务,例如一次不超过三个并行运行。

您可以创建具有有限并行度的线程池:

ExecutorService executor = Executors.newFixedThreadPool(3);

这里的挑战是您希望在任务启动时开始超时,而不是在提交任务时。 由于提交的任务无法访问自己的 Future,我将使用SynchronousQueue来等待从提交线程传递的 Future:

ScheduledExecutorService cancelScheduler =
    Executors.newSingleThreadScheduledExecutor();

for (int i : array) {
    SynchronousQueue<Runnable> cancelQueue = new SynchronousQueue<>();

    Future<?> task = executor.submit(() -> {
        Runnable canceler = cancelQueue.take();
        cancelScheduler.schedule(canceler, 5, TimeUnit.SECONDS);

        Goring goring = new Goring();
        goring.goring(i);

        return null;
    });

    cancelQueue.put(() -> task.cancel(true));
}

executor.shutdown();
cancelScheduler.shutdown();

顾名思义, Executors.newSingleThreadScheduledExecutor()只使用一个线程进行所有调度,这非常适合您的目的,因为计划任务只调用 Future.cancel,所花费的时间可以忽略不计。

return null; 在任务中,从 lambda 返回一个值使其成为 Callable 而不是 Runnable。 (Runnable 的run方法有一个返回类型void ,所以返回值的存在告诉编译器这个 lambda 不可能代表一个 Runnable。)这意味着它的签名隐含地throws Exception ,所以没有必要捕获 InterruptedException可能由cancelQueue.take()抛出。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM