我有一个数十万可调用
对象的列表。当每一个运行时,它都会根据给定的值执行一个可能很长的计算。正因为如此,我希望异步运行每个任务(最好是通过使用某种执行器),并在30秒后检索每次计算的结果,取消那些没有及时完成的结果。(所得值在其他地方使用。)
到目前为止,我就是这样实现它的:
private void process() {
class Runner implements Callable<BigDecimal> {
final int x, y;
Runner(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public BigDecimal call() {
BigDecimal gWidth = xMax.subtract(xMin), gHeight = yMax.subtract(yMin);
BigDecimal gy = gHeight.multiply(BigDecimal.valueOf(-y)).divide(BigDecimal.valueOf(height)).add(yMax);
BigDecimal gx = gWidth.multiply(BigDecimal.valueOf(x)).divide(BigDecimal.valueOf(width)).add(xMin);
// The calculation begins when this method is called
BigDecimal result = calculateAt(gx, gy);
return result;
}
}
ExecutorService exec = Executors.newCachedThreadPool();
List<Runner> runners = new ArrayList<>();
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
runners.add(new Runner(x, y));
}
}
try {
List<Future<BigDecimal>> results = exec.invokeAll(runners, 30, TimeUnit.SECONDS);
for (Future<BigDecimal> future : results) {
// Check if the future's task was cancelled and process the results
}
} catch (InterruptedException | ExecutionException ex) {
ex.printStackTrace();
}
exec.shutdown();
}
// Extra variables and methods
BigDecimal xMin = BigDecimal.valueOf(-7),
xMax = BigDecimal.valueOf(7),
yMin = BigDecimal.valueOf(-7),
yMax = BigDecimal.valueOf(7);
int height = 850, width = 850;
private BigDecimal calculateAt(BigDecimal x, BigDecimal y) {
try {
// Just to simulate a potential execution time
Thread.sleep((ThreadLocalRandom.current().nextInt(45) + 1) * 1000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
return BigDecimal.ONE;
}
ArrayListrunners
存储每个要执行的callable
,然后将其发送到ExecutorService以运行所有任务。我遇到的问题是,任务似乎是同步启动的,而在超时30秒后,只有前40或5万个任务完成了,更不用说开始执行了。
似乎正在发生的是ExecutorService.InvokeAll
方法只允许30秒的窗口用于列表中的所有任务开始和完成执行。相反,我需要的是在每个任务的基础上开始这个30秒的窗口,也就是说,一旦任务已经开始,就允许30秒的时间来完成它。InvokeAll
似乎不能做到这一点,至少在使用NewCachedThreadPool
时不能做到这一点。有Java库或其他实现方法吗?
我认为您可以使用completablefuture
来解决问题。
例如,下面是一段基于问题片段的代码:
private static final ExecutorService executor = Executors.newCachedThreadPool();
private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(100);
private static void processAsync() {
List<CompletableFuture<Object>> futureList = IntStream.range(0, height).boxed()
.flatMap(y -> IntStream.range(0, width).boxed().map(x -> new Runner(x, y)))
.map(runner ->
CompletableFuture.anyOf(
CompletableFuture.supplyAsync(runner, executor),
timeout(Duration.ofSeconds(30))
).exceptionally(throwable -> {
// timeout is handled here
return BigDecimal.ZERO;
})
)
.collect(Collectors.toList());
CompletableFuture.allOf(futureList.toArray(new CompletableFuture<?>[0]))
.thenAccept(v -> {
List<BigDecimal> results = futureList.stream()
.map(CompletableFuture::join)
.map(r -> (BigDecimal) r)
.collect(Collectors.toList());
// process final results
BigDecimal sum = results.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
System.out.println("Final sum: " + sum);
})
.exceptionally(throwable -> {
System.out.println("Failed allOf with " + throwable);
return null;
});
}
private static CompletableFuture<BigDecimal> timeout(Duration duration) {
CompletableFuture<BigDecimal> future = new CompletableFuture<>();
scheduler.schedule(
() -> future.completeExceptionally(new TimeoutException("Timeout " + Thread.currentThread().getName())), duration.toMillis(), MILLISECONDS);
return future;
}
private static class Runner implements Supplier<BigDecimal> {...
这里的主要思想是使用completablefuture.anyof
,并将其应用于有用任务的completablefuture
和超时任务的COPMPLETablefuture
。通过使用ScheduleDexecutorService
和CompletableFuture.CompleteExceptional
来实现超时。因此,基本上,anyof
返回result或TimeoutException
。
问题内容: 快速回顾一下-我有一个Java EE前端,可以接受用户请求,然后针对每个请求使用ExecutorService(SingleThreadedExecutor设置为守护程序)启动冗长的工作流,该工作流包含在库中并且可以工作很好,并且在通过Eclipse以独立模式运行时按预期运行。当从website(servlet)调用时,我观察到工作流始终在初始化Velocity Engine(Velo
我已经使用ExecutorService实现了超时任务。在下面的方法中,我正在提交超时任务,如果它在给定的时间内超时,我将取消该任务并关闭执行器。 它运行得很好,我没有任何问题。 然而,我想知道这是否是最好的代码设计。我只是想知道如果使用ExecutorService返回的未来是否会更好。submit()获取可调用函数的返回值或超时超时任务。例如 我正在使用JDK7。
2.)AVD没有互联网问题(原因稍后解释)。 3.)与我的volley singleton类或请求队列无关(原因稍后解释)。 所以我想我在Volley/Request Future的用法上犯了某种错误。
我在使用SpecifyKind时遇到问题。我发现,如果我将字符串(“O”)应用于DateTime.Now或new DateTime(),则会使spantime不同。我不知道这是怎么可能的。我尝试将这些日期时间保存为数据库中的Utc,但由于跨度不同,时间将不正确。 我就是这样做的: 现在:2021-12-08 13:40:35现在:2021-12-08T13:40:35.1159209 01:00日
问题内容: 我在应用程序中使用Gson,为此,我使用了一些名称与使用Json相同的类。我的应用程序运行良好,但是在编写proguard时,应用程序崩溃了,我猜有些类正在缩小。我的错误是: java.lang.ClassCastException:com.google.gson.internal.StringMap无法转换为com.sample.package.GsonClass 问题答案: 您需要
我使用的是NetBeans 8.1,我有一个SpringBoot项目,它具有以下依赖项: 它们都是在依赖项中正确下载的。 该项目有3个java类和一个扩展JpaRepository的接口 在src/main/资源项下- 在html标签上,我有错误:本地名称为“xmlns: th不可序列化为XML 1.0的属性。如果我试图运行该项目并转到http://localhost:8080/页面,我有一个白标