4

我想在有时间限制的后台执行一些工作。问题是,我不想阻塞主线程。

天真的实现是有两个执行器服务。一个用于调度/超时,第二个负责完成工作。

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);
        }
    }
});

还有其他解决方案吗?

4

2 回答 2

2

您不需要 ExecutorService 就可以像这样运行一个线程。您可以创建一个 FutureTask 来代替,它可以为您提供相同的好处而无需开销。

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

上述代码段中的可调用对象将是您的任务。如果您有一个 Runnable(就像您在上面的代码块中所做的那样),您可以通过以下方式将其转换为 Callable:

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

因此,总而言之,您的代码可能会更改为:

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);
        } 
    }
});

您不需要 finally 来关闭执行程序。尽管您可能仍然需要 finally 来清理任何其他资源。

于 2012-04-26T13:08:10.857 回答
0

您可以将 Executor Service 与 CompletableFuture 一起使用。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());
                    }
                });
}
于 2019-09-28T10:23:01.103 回答