简体   繁体   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

I tried using future inside executor service, it works without blocking the main thread.我尝试在执行器服务中使用未来,它可以在不阻塞主线程的情况下工作。 However this ends up creating double the amount of threads which is not desirable.然而,这最终会创建双倍数量的线程,这是不可取的。 in the code below i was able to use future.get() without blocking but i have to create double the amount of threads在下面的代码中,我能够在没有阻塞的情况下使用 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();
    
        }

Normally I would recommend using ExecutorService.invokeAll , which allows the submission of any number of tasks with a timeout and which will cancel any tasks which haven't completed when that timeout expires.通常我会推荐使用ExecutorService.invokeAll ,它允许提交任意数量的超时任务,并在超时到期时取消任何尚未完成的任务。

But you have stated in a comment that you want to be able to submit tasks in smaller parallelized groups, for example having no more than three running concurrently at a time.但是您在评论中声明您希望能够在较小的并行组中提交任务,例如一次不超过三个并行运行。

You can create a thread pool with a limited amount of parallelism:您可以创建具有有限并行度的线程池:

ExecutorService executor = Executors.newFixedThreadPool(3);

The challenge here is that you want the timeout to start when the task starts, not when the task is submitted.这里的挑战是您希望在任务启动时开始超时,而不是在提交任务时。 Since a submitted task has no way to access its own Future, I would use a SynchronousQueue to wait for that Future to be passsed from the submitting thread:由于提交的任务无法访问自己的 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();

As the name implies, Executors.newSingleThreadScheduledExecutor() uses just one thread for all scheduling, which is perfectly suitable for your purposes, since the scheduled tasks only call Future.cancel, which takes a negligible amount of time.顾名思义, Executors.newSingleThreadScheduledExecutor()只使用一个线程进行所有调度,这非常适合您的目的,因为计划任务只调用 Future.cancel,所花费的时间可以忽略不计。

The reason for having return null; return null; in the task is that returning a value from the lambda makes it a Callable rather than a Runnable.在任务中,从 lambda 返回一个值使其成为 Callable 而不是 Runnable。 (Runnable's run method has a return type of void , so the presence of a returned value tells the compiler this lambda cannot possibly represent a Runnable.) This means its signature implicitly has throws Exception in it, so there is no need to catch the InterruptedException that might be thrown by cancelQueue.take() . (Runnable 的run方法有一个返回类型void ,所以返回值的存在告诉编译器这个 lambda 不可能代表一个 Runnable。)这意味着它的签名隐含地throws Exception ,所以没有必要捕获 InterruptedException可能由cancelQueue.take()抛出。

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

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