我想在有时间限制的后台执行一些工作。问题是,我不想阻止主线程。
天真的实现是拥有两个执行器服务。一个用于调度/超时,第二个用于完成工作。
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);
}
}
});
还有其他解决方案吗?
答案 0 :(得分:2)
您不需要ExecutorService就可以像这样一次运行一个线程。您可以创建一个FutureTask,它可以在不增加开销的情况下为您提供相同的好处。
FutureTask<T> future = new FutureTask<T>(callable);
Thread thread = new Thread(future);
thread.start();
try {
future.get(120 * 1000, TimeUnit.MILLISECONDS);
} ...
上述代码段中的callable将是您的任务。 如果您有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);
}
}
});
您不需要最终关闭执行程序。虽然您可能仍希望最终清理任何其他资源。
答案 1 :(得分: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());
}
});
}