简体   繁体   English

ExecutorService的超时而没有阻塞主线程

[英]Timeout for ExecutorService without blocking the main thread

I would like to execute some work in a background with a time limit. 我想在有时间限制的背景下执行一些工作。 The thing is, I don't want to block the main thread. 问题是,我不想阻塞主线程。

Naive implementation is to have two executor services. 天真的实现是拥有两个执行程序服务。 One for scheduling/timeout and the second one will be responsible for getting work done. 一个用于计划/超时,第二个负责完成工作。

final ExecutorService backgroundExecutor = Executors.newSingleThreadExecutor();
final ExecutorService workerExecutor = Executors.newCachedThreadExecutor();


backgroundExecutor.execute(new Runnable() {
    public void run() {
        Future future = workerExecutor.submit(new Runnable() {
            public void run() {
                // do work
            }
        });
        try {
            future.get(120 * 1000, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            logger.error("InterruptedException while notifyTransactionStateChangeListeners()", e);
            future.cancel(true);
        } catch (ExecutionException e) {
            logger.error("ExecutionException", e);
        } catch (TimeoutException e) {
            logger.error("TimeoutException", e);
            future.cancel(true);
        }
    }
});

Are there any other solutions? 还有其他解决方案吗?

You don't need an ExecutorService just to run a single thread one time like that. 您不需要ExecutorService仅仅运行一次这样的单个线程。 You can create a FutureTask instead which gives you the same benefits without the overhead. 您可以创建一个FutureTask来获得相同的好处,而无需额外的开销。

FutureTask<T> future = new FutureTask<T>(callable);
Thread thread = new Thread(future);
thread.start();
try {
    future.get(120 * 1000, TimeUnit.MILLISECONDS);
} ...

The callable in the above snippet would be your task. 以上代码段中的callable将是您的任务。 If you have a Runnable (as you do in your above code block) you can turn it into a Callable via: 如果您有一个Runnable(如您在上面的代码块中所做的那样),则可以通过以下方式将其转换为Callable:

Callable callable = Executors.callable(runnable, null);

So, to summarize, your code could change to: 因此,总而言之,您的代码可以更改为:

backgroundExecutor.execute(new Runnable() {
    public void run() {

        Runnable myRunnable = new Runnable() {
            public void run() {
                // do work
            }
        } 

        Callable callable = Executors.callable(myRunnable, null);

        FutureTask<T> future = new FutureTask<T>(callable);
        Thread thread = new Thread(future);
        thread.start();

        try {
            future.get(120 * 1000, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            logger.error("InterruptedException while notifyTransactionStateChangeListeners()", e);
            future.cancel(true);
        } catch (ExecutionException e) {
            logger.error("ExecutionException", e);
        } catch (TimeoutException e) {
            logger.error("TimeoutException", e);
            future.cancel(true);
        } 
    }
});

You don't need a finally to shut down the executor. 您不需要finally关闭执行程序。 Though you might still want a finally to clean up any other resources. 尽管您可能仍然希望最终清理所有其他资源。

You can use Executor Service along with CompletableFuture. 您可以将Executor Service与CompletableFuture一起使用。 CompletableFuture runAsync accepts Runnable and ExecutorService Arguments. CompletableFuture runAsync接受Runnable和ExecutorService参数。

final ExecutorService workerExecutor = Executors.newCachedThreadExecutor();

void queueTask(TaskId taskId) {
        workerExecutor.submit(() -> processTaskAsync(taskId));
    }

private void processTaskAsync(TaskId taskId) {
        CompletableFuture.runAsync(() -> processTask(taskId), this.workerExecutor)
                .whenComplete((ok, error) -> {
                    if (error != null) {
                        log.error("Exception while processing task", error);
                    } else {
                        log.info("finished post processing for task id {}", taskId.getValue());
                    }
                });
}

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

相关问题 ExecutorService,如何知道所有线程何时完成而不阻塞主线程? - ExecutorService, how to know when all threads finished without blocking the main thread? ExecutorService-主线程关闭 - ExecutorService - shutdown of main thread 没有线程阻塞的主线程回调(Java) - Callbacks to main thread without thread blocking (Java) 如何使用 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 异步加载世界或不阻塞主线程 - load a world asynchronously or without blocking the main thread 等待回调而不会阻塞主线程 - Wait for callback without blocking main thread 从可调用线程发出异常信号,而不会阻塞主线程 - Signaling for exception from Callable thread without blocking in main thread Java在不阻塞主线程的情况下并行运行任务 - Java Run a task parallel to main thread without blocking it 如何在不阻塞主线程的情况下从supplysync返回对象? - How to return a object from supplysync without blocking the main thread? ProcessBuilder:在不阻塞主线程的情况下转发已启动进程的 stdout 和 stderr - ProcessBuilder: Forwarding stdout and stderr of started processes without blocking the main thread
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM