工作线程的Threadpool任务执行程序超时

时间:2016-11-05 22:56:11

标签: java spring asynchronous spring-boot

我正在使用spring boot并且有一个异步方法。为了执行异步,我有以下配置,问题是如果由于某种原因所有这5个线程挂起,基本上它将锁定应用程序并且不执行任何新任务(它将继续接受)。我们如何为这些工作线程设置超时,比方说120秒,所以在此之后它会超时并执行新任务。 (是的,我正在使用具有无限队列的固定线程池来继续接受任务)

@EnableAsync
@Configuration
public class AsyncConfiguration implements AsyncConfigurer {

@Override
public Executor getAsyncExecutor() {
    ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
    taskExecutor.setCorePoolSize(5);
    taskExecutor.setMaxPoolSize(5);
    taskExecutor.initialize();
    return taskExecutor;
}

@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
    return new SimpleAsyncUncaughtExceptionHandler();
}

}

3 个答案:

答案 0 :(得分:0)

您可以创建另一个执行程序,如:

static class TimeOutExecutorService extends CompletableExecutors.DelegatingCompletableExecutorService {
    private final Duration timeout;
    private final ScheduledExecutorService schedulerExecutor;

    TimeOutExecutorService(ExecutorService delegate, Duration timeout) {
        super(delegate);
        this.timeout = timeout;
        schedulerExecutor = Executors.newScheduledThreadPool(1);
    }

    @Override public <T> CompletableFuture<T> submit(Callable<T> task) {
        CompletableFuture<T> cf = new CompletableFuture<>();
        Future<?> future = delegate.submit(() -> {
            try {
                cf.complete(task.call());
            } catch (CancellationException e) {
                cf.cancel(true);
            } catch (Throwable ex) {
                cf.completeExceptionally(ex);
            }
        });

        schedulerExecutor.schedule(() -> {
            if (!cf.isDone()) {
                cf.completeExceptionally(new TimeoutException("Timeout after " + timeout));
                future.cancel(true);
            }
        }, timeout.toMillis(), TimeUnit.MILLISECONDS);
        return cf;
    }
}

然后,创建一个名为timed

的新bean
@Bean(name = "timed")
public Executor timeoutExecutor() {
    ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("timed-%d").build();
    return TimedCompletables.timed(Executors.newFixedThreadPool(10, threadFactory), Duration.ofSeconds(2));
}

并尝试使用此Executor执行异步任务。

或者,尝试从FixSizeThreadPool更改代码以构建自己的线程池执行程序。

答案 1 :(得分:0)

您不能提交一些超时的任务。您可以做的是,当您提交任务时,您将获得一个 Future 对象。您可以将此引用保留在某个 Map 和pole 中,并查看任务是否在超时后继续运行。如果是这样,您可以使用类 Future.
的方法 cancel() 或者,您自己的任务在开始运行时会将自己的当前线程放入主(提交)线程可见的某个 Map 中。此外,如果您发现您的任务没有及时完成(再次极化),您可以尝试中断您的线程。无论哪种情况,您提交的任务都应该能够对 interrupt() 类的 Thread 方法做出反应。我实际上实现了这种替代方式。如果你走这条路,测试很多...... :)

答案 2 :(得分:0)

我认为 Future.get(timeout, unit) 方法可以管理异步超时。 以下示例可以在我的本地工作。

var toReturn = await _filmCollection.Find(item => item.CompagnyOwner == compagny.CompagnyName.Contains(item.CompagnyOwner)).ToListAsync();

我们可以在应用程序启动 10 秒后获得 @SpringBootApplication @EnableScheduling @EnableAsync public class AsyncTimeoutExampleAppliation { private final MyService myService; public AsyncTimeoutExampleAppliation(MyService myService) { this.myService = myService; } public static void main(String[] args) { SpringApplication.run(AsyncTimeoutExampleAppliation.class, args); } @PostConstruct void postConstract(){ asyncCall(); } public void asyncCall(){ try { String result = myService.doSomething() .get(10, TimeUnit.SECONDS); System.out.println(result); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } catch (TimeoutException e) { e.printStackTrace(); } } @Service public static class MyService { @Async public Future<String> doSomething() throws InterruptedException { TimeUnit.SECONDS.sleep(60); return CompletableFuture.completedFuture("Finished"); } } }