optimizations, more comfortable PromiseFactory api and support virtual threaded executors

This commit is contained in:
WhatCats
2025-01-06 14:06:39 +01:00
parent 18d334a530
commit 9e392c91ba
39 changed files with 1205 additions and 833 deletions

View File

@@ -1,7 +1,5 @@
package dev.tommyjs.futur;
import dev.tommyjs.futur.executor.SinglePoolExecutor;
import dev.tommyjs.futur.impl.SimplePromiseFactory;
import dev.tommyjs.futur.promise.Promise;
import dev.tommyjs.futur.promise.PromiseFactory;
import org.junit.jupiter.api.Test;
@@ -17,24 +15,36 @@ public final class PromiseTests {
private final Logger logger = LoggerFactory.getLogger(PromiseTests.class);
private final ScheduledExecutorService executor = Executors.newScheduledThreadPool(5);
private final PromiseFactory pfac = new SimplePromiseFactory<>(new SinglePoolExecutor(executor), logger);
private final PromiseFactory promises = PromiseFactory.of(logger, executor);
@Test
public void testErrors() {
Promise<?> promise = promises.start().thenSupplyAsync(() -> {
throw new StackOverflowError();
});
try {
promise.await();
} catch (CompletionException e) {
assert e.getCause() instanceof StackOverflowError;
}
}
@Test
public void testShutdown() {
executor.shutdown();
Promise<?> promise = pfac.resolve(null).thenSupplyAsync(() -> null);
executor.close();
Promise<?> promise = promises.resolve(null).thenSupplyAsync(() -> null);
try {
promise.await();
} catch (RuntimeException e) {
} catch (CompletionException e) {
assert e.getCause() instanceof RejectedExecutionException;
}
}
@Test
public void testErrorCancellation() throws InterruptedException {
public void testCancellation() throws InterruptedException {
var finished = new AtomicBoolean();
pfac.start()
.thenRunDelayedAsync(() -> finished.set(true), 50, TimeUnit.MILLISECONDS)
promises.start().thenRunDelayedAsync(() -> finished.set(true), 50, TimeUnit.MILLISECONDS)
.thenRunAsync(() -> {})
.cancel();
@@ -44,11 +54,11 @@ public final class PromiseTests {
@Test
public void testToFuture() throws InterruptedException {
assert pfac.resolve(true).toFuture().getNow(false);
assert pfac.error(new Exception("Test")).toFuture().isCompletedExceptionally();
assert promises.resolve(true).toFuture().getNow(false);
assert promises.error(new Exception("Test")).toFuture().isCompletedExceptionally();
var finished = new AtomicBoolean();
pfac.start()
promises.start()
.thenRunDelayedAsync(() -> finished.set(true), 50, TimeUnit.MILLISECONDS)
.toFuture()
.cancel(true);
@@ -58,86 +68,81 @@ public final class PromiseTests {
}
@Test
public void testCombineUtil() throws TimeoutException {
pfac.all(
pfac.start().thenRunDelayedAsync(() -> {}, 50, TimeUnit.MILLISECONDS),
pfac.start().thenRunDelayedAsync(() -> {}, 50, TimeUnit.MILLISECONDS)
public void testCombineUtil() throws TimeoutException, ExecutionException, InterruptedException {
promises.all(
promises.start().thenRunDelayedAsync(() -> {}, 50, TimeUnit.MILLISECONDS),
promises.start().thenRunDelayedAsync(() -> {}, 50, TimeUnit.MILLISECONDS)
)
.join(100L);
.get(100L, TimeUnit.MILLISECONDS);
pfac.allSettled(
pfac.start().thenRunDelayedAsync(() -> {}, 50, TimeUnit.MILLISECONDS),
pfac.start().thenRunDelayedAsync(() -> {}, 50, TimeUnit.MILLISECONDS)
promises.allSettled(
promises.start().thenRunDelayedAsync(() -> {}, 50, TimeUnit.MILLISECONDS),
promises.start().thenRunDelayedAsync(() -> {}, 50, TimeUnit.MILLISECONDS)
)
.join(100L);
.get(100L, TimeUnit.MILLISECONDS);
pfac.combine(
pfac.start().thenRunDelayedAsync(() -> {}, 50, TimeUnit.MILLISECONDS),
pfac.start().thenRunDelayedAsync(() -> {}, 50, TimeUnit.MILLISECONDS)
promises.combine(
promises.start().thenRunDelayedAsync(() -> {}, 50, TimeUnit.MILLISECONDS),
promises.start().thenRunDelayedAsync(() -> {}, 50, TimeUnit.MILLISECONDS)
)
.join(100L);
.get(100L, TimeUnit.MILLISECONDS);
pfac.combine(
promises.combine(
List.of(
pfac.start().thenRunDelayedAsync(() -> {}, 49, TimeUnit.MILLISECONDS),
pfac.start().thenRunDelayedAsync(() -> {}, 50, TimeUnit.MILLISECONDS),
pfac.start().thenRunDelayedAsync(() -> {}, 51, TimeUnit.MILLISECONDS)
promises.start().thenRunDelayedAsync(() -> {}, 49, TimeUnit.MILLISECONDS),
promises.start().thenRunDelayedAsync(() -> {}, 50, TimeUnit.MILLISECONDS),
promises.start().thenRunDelayedAsync(() -> {}, 51, TimeUnit.MILLISECONDS)
)
)
.join(100L);
.get(100L, TimeUnit.MILLISECONDS);
pfac.combine(
promises.combine(
Map.of(
"a", pfac.start().thenRunDelayedAsync(() -> {}, 50, TimeUnit.MILLISECONDS),
"b", pfac.start().thenRunDelayedAsync(() -> {}, 50, TimeUnit.MILLISECONDS)
"a", promises.start().thenRunDelayedAsync(() -> {}, 50, TimeUnit.MILLISECONDS),
"b", promises.start().thenRunDelayedAsync(() -> {}, 50, TimeUnit.MILLISECONDS)
)
)
.join(100L);
.get(100L, TimeUnit.MILLISECONDS);
}
@Test
public void testCombineUtilPropagation() throws InterruptedException {
var finished1 = new AtomicBoolean();
pfac.all(
true,
pfac.start().thenRunDelayedAsync(() -> finished1.set(true), 50, TimeUnit.MILLISECONDS),
pfac.start().thenRunDelayedAsync(() -> finished1.set(true), 50, TimeUnit.MILLISECONDS)
promises.all(
promises.start().thenRunDelayedAsync(() -> finished1.set(true), 50, TimeUnit.MILLISECONDS),
promises.start().thenRunDelayedAsync(() -> finished1.set(true), 50, TimeUnit.MILLISECONDS)
)
.cancel();
var finished2 = new AtomicBoolean();
pfac.allSettled(
true,
pfac.start().thenRunDelayedAsync(() -> finished2.set(true), 50, TimeUnit.MILLISECONDS),
pfac.start().thenRunDelayedAsync(() -> finished2.set(true), 50, TimeUnit.MILLISECONDS)
promises.allSettled(
promises.start().thenRunDelayedAsync(() -> finished2.set(true), 50, TimeUnit.MILLISECONDS),
promises.start().thenRunDelayedAsync(() -> finished2.set(true), 50, TimeUnit.MILLISECONDS)
)
.cancel();
var finished3 = new AtomicBoolean();
pfac.combine(
true,
pfac.start().thenRunDelayedAsync(() -> finished3.set(true), 50, TimeUnit.MILLISECONDS),
pfac.start().thenRunDelayedAsync(() -> finished3.set(true), 50, TimeUnit.MILLISECONDS)
promises.combine(
promises.start().thenRunDelayedAsync(() -> finished3.set(true), 50, TimeUnit.MILLISECONDS),
promises.start().thenRunDelayedAsync(() -> finished3.set(true), 50, TimeUnit.MILLISECONDS)
)
.cancel();
var finished4 = new AtomicBoolean();
pfac.combine(
true,
promises.combine(
List.of(
pfac.start().thenRunDelayedAsync(() -> finished4.set(true), 50, TimeUnit.MILLISECONDS),
pfac.start().thenRunDelayedAsync(() -> finished4.set(true), 50, TimeUnit.MILLISECONDS),
pfac.start().thenRunDelayedAsync(() -> finished4.set(true), 50, TimeUnit.MILLISECONDS)
promises.start().thenRunDelayedAsync(() -> finished4.set(true), 50, TimeUnit.MILLISECONDS),
promises.start().thenRunDelayedAsync(() -> finished4.set(true), 50, TimeUnit.MILLISECONDS),
promises.start().thenRunDelayedAsync(() -> finished4.set(true), 50, TimeUnit.MILLISECONDS)
)
)
.cancel();
var finished5 = new AtomicBoolean();
pfac.combine(
true,
promises.combine(
Map.of(
"a", pfac.start().thenRunDelayedAsync(() -> finished5.set(true), 50, TimeUnit.MILLISECONDS),
"b", pfac.start().thenRunDelayedAsync(() -> finished5.set(true), 50, TimeUnit.MILLISECONDS)
"a", promises.start().thenRunDelayedAsync(() -> finished5.set(true), 50, TimeUnit.MILLISECONDS),
"b", promises.start().thenRunDelayedAsync(() -> finished5.set(true), 50, TimeUnit.MILLISECONDS)
)
)
.cancel();
@@ -151,13 +156,13 @@ public final class PromiseTests {
}
@Test
public void testRace() throws TimeoutException {
assert pfac.race(
public void testRace() {
assert promises.race(
List.of(
pfac.start().thenSupplyDelayedAsync(() -> true, 150, TimeUnit.MILLISECONDS),
pfac.start().thenSupplyDelayedAsync(() -> false, 200, TimeUnit.MILLISECONDS)
promises.start().thenSupplyDelayedAsync(() -> true, 150, TimeUnit.MILLISECONDS),
promises.start().thenSupplyDelayedAsync(() -> false, 200, TimeUnit.MILLISECONDS)
)
).join(300L);
).await();
}
}