BAEL-6578: CompletableFuture allOf.join() vs join()

This commit is contained in:
emanuel.trandafir 2023-07-15 19:53:51 +02:00
parent 296bba8657
commit 6fbb898059
1 changed files with 112 additions and 0 deletions

View File

@ -0,0 +1,112 @@
package com.baeldung.concurrent.completablefuture.allofvsjoin;
import static org.junit.Assert.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import java.time.LocalDateTime;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Stream;
import org.junit.jupiter.api.Test;
public class CompletableFutureAllOffUnitTest {
@Test
void whenCallingJoin_thenBlocksThreadAndGetValue() {
CompletableFuture<String> future = waitAndReturn(1_000, "Harry");
assertEquals("Harry", future.join()); // waits one second
}
@Test
void whenCallingJoin_thenBlocksThreadAndThrowException() {
CompletableFuture<String> futureError = waitAndThrow(1_000);
assertThrows(RuntimeException.class, futureError::join); // waits one second
}
@Test
void whenCallingJoinTwoTimes_thenBlocksThreadAndGetValues() {
CompletableFuture<String> f1 = waitAndReturn(1_000, "Harry");
CompletableFuture<String> f2 = waitAndReturn(2_000, "Ron");
assertEquals("Harry", f1.join()); // waits for one second
assertEquals("Ron", f2.join()); // waits for one more second
}
@Test
void whenCallingAllOfJoin_thenBlocksThreadAndGetValues() {
CompletableFuture<String> f1 = waitAndReturn(1_000, "Harry");
CompletableFuture<String> f2 = waitAndReturn(2_000, "Ron");
CompletableFuture<Void> combinedFutures = CompletableFuture.allOf(f1, f2); // does NOT wait
combinedFutures.join(); // waits for two seconds
assertEquals("Harry", f1.join()); // does NOT wait
assertEquals("Ron", f2.join()); // does NOT wait
}
@Test
void whenCallingJoinInaLoop_thenProcessesDataPartially() {
CompletableFuture<String> f1 = waitAndReturn(1_000, "Harry");
CompletableFuture<String> f2 = waitAndThrow(2_000);
CompletableFuture<String> f3 = waitAndReturn(1_000, "Ron");
assertThrows(RuntimeException.class, () -> Stream.of(f1, f2, f3)
.map(CompletableFuture::join)
.forEach(this::sayHello));
}
@Test
void whenCallingAllOfJoin_thenFailsForAll() {
CompletableFuture<String> f1 = waitAndReturn(1_000, "Harry");
CompletableFuture<String> f2 = waitAndThrow(2_000);
CompletableFuture<String> f3 = waitAndReturn(1_000, "Ron");
assertThrows(RuntimeException.class, () -> CompletableFuture.allOf(f1, f2, f3)
.join());
}
@Test
void whenCallingExceptionally_thenRecoversWithDefaultValue() {
CompletableFuture<String> f1 = waitAndReturn(1_000, "Harry");
CompletableFuture<String> f2 = waitAndThrow(2_000);
CompletableFuture<String> f3 = waitAndReturn(1_000, "Ron");
CompletableFuture<String> names = CompletableFuture.allOf(f1, f2, f3)
.thenApply(__ -> f1.join() + "," + f2.join() + "," + f3.join())
.exceptionally(err -> {
System.out.println("oops, there was a problem! " + err.getMessage());
return "names not found!";
});
assertEquals("names not found!", names.join());
}
private void sayHello(String name) {
System.out.println(LocalDateTime.now() + " - " + name);
}
private CompletableFuture<String> waitAndReturn(long millis, String value) {
return CompletableFuture.supplyAsync(() -> {
try {
// Thread.sleep() is commented to avoid slowing down the pipeline
// Thread.sleep(millis);
return value;
} catch (Exception e) {
throw new RuntimeException(e);
}
});
}
private CompletableFuture<String> waitAndThrow(long millis) {
return CompletableFuture.supplyAsync(() -> {
try {
// Thread.sleep() is commented to avoid slowing down the pipeline
// Thread.sleep(millis);
} finally {
throw new RuntimeException();
}
});
}
}