release 2.1.0

This commit is contained in:
tommyskeff
2024-03-12 07:27:51 +00:00
parent 49b701c736
commit 795ce04eb4
15 changed files with 143 additions and 56 deletions

View File

@@ -6,7 +6,7 @@ plugins {
} }
group = "dev.tommyjs" group = "dev.tommyjs"
version = "2.0.0" version = "2.1.0"
repositories { repositories {
mavenCentral() mavenCentral()

View File

@@ -0,0 +1,33 @@
package dev.tommyjs.futur.executor;
import org.jetbrains.annotations.NotNull;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class DualPoolExecutor implements PromiseExecutor {
private final @NotNull ScheduledExecutorService syncSvc;
private final @NotNull ScheduledExecutorService asyncSvc;
public DualPoolExecutor(@NotNull ScheduledExecutorService syncSvc, @NotNull ScheduledExecutorService asyncSvc) {
this.syncSvc = syncSvc;
this.asyncSvc = asyncSvc;
}
@Override
public void runSync(@NotNull Runnable task, long delay, @NotNull TimeUnit unit) {
syncSvc.schedule(task, delay, unit);
}
@Override
public void runAsync(@NotNull Runnable task, long delay, @NotNull TimeUnit unit) {
asyncSvc.schedule(task, delay, unit);
}
public static @NotNull DualPoolExecutor create(int asyncPoolSize) {
return new DualPoolExecutor(Executors.newSingleThreadScheduledExecutor(), Executors.newScheduledThreadPool(asyncPoolSize));
}
}

View File

@@ -0,0 +1,13 @@
package dev.tommyjs.futur.executor;
import org.jetbrains.annotations.NotNull;
import java.util.concurrent.TimeUnit;
public interface PromiseExecutor {
void runSync(@NotNull Runnable task, long delay, @NotNull TimeUnit unit);
void runAsync(@NotNull Runnable task, long delay, @NotNull TimeUnit unit);
}

View File

@@ -0,0 +1,31 @@
package dev.tommyjs.futur.executor;
import org.jetbrains.annotations.NotNull;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class SinglePoolExecutor implements PromiseExecutor {
private final @NotNull ScheduledExecutorService service;
public SinglePoolExecutor(@NotNull ScheduledExecutorService service) {
this.service = service;
}
@Override
public void runSync(@NotNull Runnable task, long delay, @NotNull TimeUnit unit) {
service.schedule(task, delay, unit);
}
@Override
public void runAsync(@NotNull Runnable task, long delay, @NotNull TimeUnit unit) {
service.schedule(task, delay, unit);
}
public static @NotNull SinglePoolExecutor create(int threadPoolSize) {
return new SinglePoolExecutor(Executors.newScheduledThreadPool(threadPoolSize));
}
}

View File

@@ -1,25 +1,24 @@
package dev.tommyjs.futur.impl; package dev.tommyjs.futur.impl;
import dev.tommyjs.futur.executor.PromiseExecutor;
import dev.tommyjs.futur.promise.AbstractPromise; import dev.tommyjs.futur.promise.AbstractPromise;
import dev.tommyjs.futur.promise.PromiseFactory; import dev.tommyjs.futur.promise.PromiseFactory;
import org.slf4j.Logger; import org.slf4j.Logger;
import java.util.concurrent.ScheduledExecutorService;
public class SimplePromise<T> extends AbstractPromise<T> { public class SimplePromise<T> extends AbstractPromise<T> {
private final ScheduledExecutorService executor; private final PromiseExecutor executor;
private final Logger logger; private final Logger logger;
private final PromiseFactory factory; private final PromiseFactory factory;
public SimplePromise(ScheduledExecutorService executor, Logger logger, PromiseFactory factory) { public SimplePromise(PromiseExecutor executor, Logger logger, PromiseFactory factory) {
this.executor = executor; this.executor = executor;
this.logger = logger; this.logger = logger;
this.factory = factory; this.factory = factory;
} }
@Override @Override
protected ScheduledExecutorService getExecutor() { protected PromiseExecutor getExecutor() {
return executor; return executor;
} }

View File

@@ -1,19 +1,18 @@
package dev.tommyjs.futur.impl; package dev.tommyjs.futur.impl;
import dev.tommyjs.futur.executor.PromiseExecutor;
import dev.tommyjs.futur.promise.AbstractPromise; import dev.tommyjs.futur.promise.AbstractPromise;
import dev.tommyjs.futur.promise.Promise; import dev.tommyjs.futur.promise.Promise;
import dev.tommyjs.futur.promise.PromiseFactory; import dev.tommyjs.futur.promise.PromiseFactory;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger; import org.slf4j.Logger;
import java.util.concurrent.ScheduledExecutorService;
public class SimplePromiseFactory implements PromiseFactory { public class SimplePromiseFactory implements PromiseFactory {
private final ScheduledExecutorService executor; private final PromiseExecutor executor;
private final Logger logger; private final Logger logger;
public SimplePromiseFactory(ScheduledExecutorService executor, Logger logger) { public SimplePromiseFactory(PromiseExecutor executor, Logger logger) {
this.executor = executor; this.executor = executor;
this.logger = logger; this.logger = logger;
} }

View File

@@ -1,13 +1,14 @@
package dev.tommyjs.futur.promise; package dev.tommyjs.futur.impl;
import dev.tommyjs.futur.executor.PromiseExecutor;
import dev.tommyjs.futur.promise.AbstractPromise;
import dev.tommyjs.futur.promise.PromiseFactory;
import org.slf4j.Logger; import org.slf4j.Logger;
import java.util.concurrent.ScheduledExecutorService;
public class StaticPromise<T> extends AbstractPromise<T> { public class StaticPromise<T> extends AbstractPromise<T> {
@Override @Override
protected ScheduledExecutorService getExecutor() { protected PromiseExecutor getExecutor() {
return StaticPromiseFactory.EXECUTOR; return StaticPromiseFactory.EXECUTOR;
} }

View File

@@ -1,21 +1,25 @@
package dev.tommyjs.futur.promise; package dev.tommyjs.futur.impl;
import dev.tommyjs.futur.executor.PromiseExecutor;
import dev.tommyjs.futur.executor.SinglePoolExecutor;
import dev.tommyjs.futur.promise.AbstractPromise;
import dev.tommyjs.futur.promise.Promise;
import dev.tommyjs.futur.promise.PromiseFactory;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
public class StaticPromiseFactory implements PromiseFactory { public class StaticPromiseFactory implements PromiseFactory {
public static final @NotNull PromiseFactory INSTANCE; public static final @NotNull PromiseFactory INSTANCE;
public static final @NotNull ScheduledExecutorService EXECUTOR; public static final @NotNull PromiseExecutor EXECUTOR;
public static final @NotNull Logger LOGGER; public static final @NotNull Logger LOGGER;
static { static {
INSTANCE = new StaticPromiseFactory(); INSTANCE = new StaticPromiseFactory();
EXECUTOR = Executors.newSingleThreadScheduledExecutor(); EXECUTOR = SinglePoolExecutor.create(1);
LOGGER = LoggerFactory.getLogger(StaticPromiseFactory.class); LOGGER = LoggerFactory.getLogger(StaticPromiseFactory.class);
} }
@@ -25,7 +29,7 @@ public class StaticPromiseFactory implements PromiseFactory {
@Override @Override
public @NotNull <T> Promise<T> resolve(T value) { public @NotNull <T> Promise<T> resolve(T value) {
AbstractPromise<T> promise = new StaticPromise<>(); AbstractPromise<T> promise = new StaticPromise<>();
promise.setCompletion(new PromiseCompletion<>(value)); promise.complete(value);
return promise; return promise;
} }

View File

@@ -1,5 +1,6 @@
package dev.tommyjs.futur.promise; package dev.tommyjs.futur.promise;
import dev.tommyjs.futur.executor.PromiseExecutor;
import dev.tommyjs.futur.function.ExceptionalConsumer; import dev.tommyjs.futur.function.ExceptionalConsumer;
import dev.tommyjs.futur.function.ExceptionalFunction; import dev.tommyjs.futur.function.ExceptionalFunction;
import dev.tommyjs.futur.function.ExceptionalRunnable; import dev.tommyjs.futur.function.ExceptionalRunnable;
@@ -10,7 +11,6 @@ import org.slf4j.Logger;
import java.util.Collection; import java.util.Collection;
import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException; import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
@@ -18,15 +18,14 @@ import java.util.concurrent.atomic.AtomicReference;
public abstract class AbstractPromise<T> implements Promise<T> { public abstract class AbstractPromise<T> implements Promise<T> {
private final Collection<PromiseListener<T>> listeners; private final Collection<PromiseListener<T>> listeners;
private final AtomicReference<PromiseCompletion<T>> completion;
private @Nullable PromiseCompletion<T> completion;
public AbstractPromise() { public AbstractPromise() {
this.listeners = new ConcurrentLinkedQueue<>(); this.listeners = new ConcurrentLinkedQueue<>();
this.completion = null; this.completion = new AtomicReference<>();
} }
protected abstract ScheduledExecutorService getExecutor(); protected abstract PromiseExecutor getExecutor();
protected abstract Logger getLogger(); protected abstract Logger getLogger();
@@ -109,7 +108,7 @@ public abstract class AbstractPromise<T> implements Promise<T> {
} }
Runnable runnable = createRunnable(ctx, promise, task); Runnable runnable = createRunnable(ctx, promise, task);
getExecutor().submit(runnable); getExecutor().runSync(runnable, 0L, TimeUnit.MILLISECONDS);
}); });
return promise; return promise;
@@ -126,7 +125,7 @@ public abstract class AbstractPromise<T> implements Promise<T> {
} }
Runnable runnable = createRunnable(ctx, promise, task); Runnable runnable = createRunnable(ctx, promise, task);
getExecutor().schedule(runnable, delay, unit); getExecutor().runSync(runnable, delay, unit);
}); });
return promise; return promise;
@@ -216,7 +215,7 @@ public abstract class AbstractPromise<T> implements Promise<T> {
} }
Runnable runnable = createRunnable(ctx, promise, task); Runnable runnable = createRunnable(ctx, promise, task);
getExecutor().submit(runnable); getExecutor().runAsync(runnable, 0L, TimeUnit.MILLISECONDS);
}); });
return promise; return promise;
@@ -227,7 +226,7 @@ public abstract class AbstractPromise<T> implements Promise<T> {
Promise<V> promise = getFactory().unresolved(); Promise<V> promise = getFactory().unresolved();
addListener(ctx -> { addListener(ctx -> {
Runnable runnable = createRunnable(ctx, promise, task); Runnable runnable = createRunnable(ctx, promise, task);
getExecutor().schedule(runnable, delay, unit); getExecutor().runAsync(runnable, delay, unit);
}); });
return promise; return promise;
@@ -285,14 +284,14 @@ public abstract class AbstractPromise<T> implements Promise<T> {
@Override @Override
public @NotNull Promise<T> addListener(@NotNull PromiseListener<T> listener) { public @NotNull Promise<T> addListener(@NotNull PromiseListener<T> listener) {
if (isCompleted()) { if (isCompleted()) {
getExecutor().submit(() -> { getExecutor().runAsync(() -> {
try { try {
//noinspection ConstantConditions //noinspection ConstantConditions
listener.handle(getCompletion()); listener.handle(getCompletion());
} catch (Exception e) { } catch (Exception e) {
getLogger().error("Exception caught in promise listener", e); getLogger().error("Exception caught in promise listener", e);
} }
}); }, 0L, TimeUnit.MILLISECONDS);
} else { } else {
getListeners().add(listener); getListeners().add(listener);
} }
@@ -302,7 +301,7 @@ public abstract class AbstractPromise<T> implements Promise<T> {
@Override @Override
public @NotNull Promise<T> timeout(long time, @NotNull TimeUnit unit) { public @NotNull Promise<T> timeout(long time, @NotNull TimeUnit unit) {
getExecutor().schedule(() -> { getExecutor().runAsync(() -> {
if (!isCompleted()) { if (!isCompleted()) {
completeExceptionally(new TimeoutException("Promise timed out after " + time + " " + unit)); completeExceptionally(new TimeoutException("Promise timed out after " + time + " " + unit));
} }
@@ -317,10 +316,23 @@ public abstract class AbstractPromise<T> implements Promise<T> {
} }
protected void handleCompletion(@NotNull PromiseCompletion<T> ctx) { protected void handleCompletion(@NotNull PromiseCompletion<T> ctx) {
if (this.isCompleted()) return; AtomicReference<Boolean> success = new AtomicReference<>();
setCompletion(ctx); completion.getAndUpdate(c -> {
if (c == null) {
return null;
} else {
success.set(true);
return ctx;
}
});
getExecutor().submit(() -> { if (success.get()) {
handleCompletion0(ctx);
}
}
protected void handleCompletion0(@NotNull PromiseCompletion<T> ctx) {
getExecutor().runAsync(() -> {
for (PromiseListener<T> listener : getListeners()) { for (PromiseListener<T> listener : getListeners()) {
if (!ctx.isActive()) return; if (!ctx.isActive()) return;
@@ -331,7 +343,7 @@ public abstract class AbstractPromise<T> implements Promise<T> {
getLogger().error("Exception caught in promise listener", e); getLogger().error("Exception caught in promise listener", e);
} }
} }
}); }, 0L, TimeUnit.MILLISECONDS);
} }
@Override @Override
@@ -346,20 +358,16 @@ public abstract class AbstractPromise<T> implements Promise<T> {
@Override @Override
public boolean isCompleted() { public boolean isCompleted() {
return getCompletion() != null; return completion.get() != null;
}
@Override
public @Nullable PromiseCompletion<T> getCompletion() {
return completion.get();
} }
protected Collection<PromiseListener<T>> getListeners() { protected Collection<PromiseListener<T>> getListeners() {
return listeners; return listeners;
} }
@Override
public @Nullable PromiseCompletion<T> getCompletion() {
return completion;
}
protected void setCompletion(@NotNull PromiseCompletion<T> completion) {
this.completion = completion;
}
} }

View File

@@ -1,12 +1,13 @@
package dev.tommyjs.futur.promise; package dev.tommyjs.futur.promise;
import dev.tommyjs.futur.executor.PromiseExecutor;
import dev.tommyjs.futur.executor.SinglePoolExecutor;
import dev.tommyjs.futur.impl.SimplePromiseFactory; import dev.tommyjs.futur.impl.SimplePromiseFactory;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
public interface PromiseFactory { public interface PromiseFactory {
@@ -16,16 +17,16 @@ public interface PromiseFactory {
<T> @NotNull Promise<T> error(Throwable error); <T> @NotNull Promise<T> error(Throwable error);
static PromiseFactory create(ScheduledExecutorService executor, Logger logger) { static PromiseFactory create(PromiseExecutor executor, Logger logger) {
return new SimplePromiseFactory(executor, logger); return new SimplePromiseFactory(executor, logger);
} }
static PromiseFactory create(ScheduledExecutorService executor) { static PromiseFactory create(PromiseExecutor executor) {
return create(executor, LoggerFactory.getLogger(SimplePromiseFactory.class)); return create(executor, LoggerFactory.getLogger(SimplePromiseFactory.class));
} }
static PromiseFactory create(int threadPoolSize) { static PromiseFactory create(int threadPoolSize) {
return create(Executors.newScheduledThreadPool(threadPoolSize)); return create(SinglePoolExecutor.create(threadPoolSize));
} }
static PromiseFactory create() { static PromiseFactory create() {

View File

@@ -6,7 +6,7 @@ plugins {
} }
group = "dev.tommyjs" group = "dev.tommyjs"
version = "2.0.0" version = "2.1.0"
repositories { repositories {
mavenCentral() mavenCentral()

View File

@@ -2,7 +2,6 @@ package dev.tommyjs.futur.reactivestreams;
import dev.tommyjs.futur.promise.Promise; import dev.tommyjs.futur.promise.Promise;
import dev.tommyjs.futur.promise.PromiseFactory; import dev.tommyjs.futur.promise.PromiseFactory;
import dev.tommyjs.futur.promise.StaticPromiseFactory;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.reactivestreams.Publisher; import org.reactivestreams.Publisher;

View File

@@ -2,7 +2,7 @@ package dev.tommyjs.futur.reactivestreams;
import dev.tommyjs.futur.promise.Promise; import dev.tommyjs.futur.promise.Promise;
import dev.tommyjs.futur.promise.PromiseFactory; import dev.tommyjs.futur.promise.PromiseFactory;
import dev.tommyjs.futur.promise.StaticPromiseFactory; import dev.tommyjs.futur.impl.StaticPromiseFactory;
import org.reactivestreams.Subscriber; import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription; import org.reactivestreams.Subscription;

View File

@@ -4,7 +4,7 @@ plugins {
} }
group = "dev.tommyjs" group = "dev.tommyjs"
version = "2.0.0" version = "2.1.0"
repositories { repositories {
mavenCentral() mavenCentral()

View File

@@ -2,7 +2,6 @@ package dev.tommyjs.futur.reactor;
import dev.tommyjs.futur.promise.Promise; import dev.tommyjs.futur.promise.Promise;
import dev.tommyjs.futur.promise.PromiseFactory; import dev.tommyjs.futur.promise.PromiseFactory;
import dev.tommyjs.futur.promise.StaticPromiseFactory;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import reactor.core.publisher.Flux; import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;