我在做
CompletableFuture.anyOf(manyfutures).thenRun( new Runnable() { } }
但是runnable中的代码只运行一次!每当任何期货完成时,我都期待它会多次运行。
每当任何期货完成时,我如何运行一段代码?以最佳方式,这意味着不会:
public static void append(final CompletableFuture[] futures, Runnable runnable) {
for (CompletableFuture future : futures) {
future.thenRun(runnable);
}
}
修改
我正在使用一个ThreadPoolExecutor,我想在执行X个runnables时附加更多的工作。
有没有办法倾听这个并在发生这种情况时提供更多工作?
另一种选择是我在开始时堆叠了数千个工作,但这也不是最佳的。
我在做
... queue = new LinkedBlockingQueue<Runnable>();
new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, queue);
答案 0 :(得分:4)
查看JavaDoc
返回任何一个新的
CompletableFuture
给定CompletableFutures
完成,结果相同。否则,如果 它完成异常,返回的CompletableFuture
也是如此 因此,CompletionException
将此异常作为原因。如果 没有提供CompletableFutures
,返回不完整CompletableFuture
。
当给定CompletableFutures
的任何完成时,该方法返回。即第一个。方法不能多次返回。
要在每个 CompletableFuture
之后运行某个操作,只需在每个 theRun
上调用thenRunAsync
或CompletableFuture
。< / p>
如果您有一个List<CompletableFuture<T>>
,并且想要一个CompletableFuture<List<T>>
,即您希望将一组期货“展开”到一个集合的未来,您可以使用这个技巧:
private static <T> CompletableFuture<List<T>> sequence(List<CompletableFuture<T>> futures) {
final CompletableFuture<Void> allDoneFuture = CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()]));
return allDoneFuture.thenApply(v ->
futures.stream().
map(future -> future.join()).
collect(toList())
);
}
答案 1 :(得分:1)
这是我追踪这个问题的答案,这个方法需要一些参数才能让人感觉良好:
/** Basically creates to-start number of futures in a while loop, while passing the index to a Lambda that is passed and that returns a Runnable which will have access to the index. See example below. **/
public static CompletableFuture[] async(ExecutorService executorService, int start, int to, Runnable beforeAll, Lambda.R1<Runnable, Integer> onEach, Double onPercentage, Runnable onPercentageRun, Runnable afterAll) {
CompletableFuture[] futures = new CompletableFuture[to-start];
double onPercentageIndex = Valid.elvis(onPercentage, 0.0) * futures.length; // When to onPercentageRun
AtomicBoolean percentageMet = new AtomicBoolean ( false );
AtomicBoolean completeMet = new AtomicBoolean ( false );
AtomicInteger complete = new AtomicInteger ( 0 );
int i = start;
if ( i < to && beforeAll != null ) {
beforeAll.run();
}
boolean percentageSet = onPercentageIndex > 0.0 && onPercentageRun != null;
boolean completeSet = afterAll != null;
while( i < to ) {
Runnable call = onEach.call(i);
futures[i-start] = CompletableFuture.runAsync(
() -> {
try {
call.run();
} catch (Throwable e) {
$Log.info(Concurrency.class, "RunAsync: run", e);
}
if ( percentageSet || completeSet ) {
complete.incrementAndGet();
if ( percentageSet && !percentageMet.get() && complete.get() >= onPercentageIndex) {
percentageMet.set(true);
try {
onPercentageRun.run();
}
catch(Throwable e) {
$Log.info(Concurrency.class, "RunAsync: onPercentage", e);
}
}
if ( completeSet && !completeMet.get() && complete.get() == to ) {
completeMet.set(true); // Just for clarity, propably redundant
try {
afterAll.run();
}
catch(Throwable e) {
$Log.info(Concurrency.class, "RunAsync: onComplete", e);
}
}
}
},
executorService
);
++i;
}
return futures;
}
有关Lambda.R1的参考,请参阅此Lambda interfaces
该方法可以这样使用:
private void recursivelyPopulateDataFiles(long fromId) {
List<Localfile> unproccessed = DB.fetchAllFilesFromId(fromId, limit);
if ( unproccessed.size() > 0 ) {
Concurrency.async(
THE_EXECUTOR,
0,
unproccessed.size(),
ITERATIONS_COUNTER_IN_PROGRESS_CAN_BE_USED_BY_OTHERS_TO_LISTEN_GLOBALLY_FOR_WHEN_IT_HITS_ZERO_AGAIN::incrementAndGet,
(Integer index) -> () -> {
populateDataFile( unproccessed.get(index) );
},
0.5,
() -> {
recursivelyPopulateDataFiles(unproccessed.get(unproccessed.size() - 1).getId());
},
ITERATIONS_COUNTER_IN_PROGRESS_CAN_BE_USED_BY_OTHERS_TO_LISTEN_GLOBALLY_FOR_WHEN_IT_HITS_ZERO_AGAIN::decrementAndGet
);
}
}
当0.5 =未完成大小的50%时,块执行后执行以在执行程序上放置更多。