我正在使用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();
}
}
答案 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(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");
}
}
}
。