有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

ExecutorService的java超时而不阻塞主线程

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

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

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

还有其他解决办法吗


共 (2) 个答案

  1. # 1 楼答案

    你不需要一个ExecutorService只运行一个线程一次。您可以创建一个FutureTask,它在不增加开销的情况下为您提供相同的好处

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

    上面代码段中的可调用项将是您的任务。 如果您有一个可运行的(正如您在上面的代码块中所做的),您可以通过以下方式将其转换为可调用的:

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

    你不需要最后一个命令来关闭遗嘱执行人。尽管您可能仍然希望最终清理任何其他资源

  2. # 2 楼答案

    您可以将Executor服务与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());
                        }
                    });
    }