
org.rx.core.ThreadPool Maven / Gradle / Ivy
package org.rx.core;
import io.netty.util.HashedWheelTimer;
import io.netty.util.Timeout;
import io.netty.util.TimerTask;
import io.netty.util.concurrent.DefaultThreadFactory;
import io.netty.util.concurrent.FastThreadLocal;
import io.netty.util.concurrent.FastThreadLocalThread;
import io.netty.util.internal.InternalThreadLocalMap;
import lombok.Getter;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.rx.bean.*;
import org.rx.exception.InvalidException;
import org.rx.exception.TraceHandler;
import org.rx.util.function.Action;
import org.rx.util.function.BiAction;
import org.rx.util.function.Func;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.*;
import static org.rx.core.Constants.NON_UNCHECKED;
import static org.rx.core.Extends.require;
@SuppressWarnings(NON_UNCHECKED)
@Slf4j
public class ThreadPool extends ThreadPoolExecutor {
@RequiredArgsConstructor
@Getter
public static class MultiTaskFuture {
final CompletableFuture future;
final CompletableFuture[] subFutures;
}
@RequiredArgsConstructor
public static class ThreadQueue extends LinkedTransferQueue {
private static final long serialVersionUID = 4283369202482437480L;
private ThreadPool pool;
final int queueCapacity;
final AtomicInteger counter = new AtomicInteger();
public boolean isFullLoad() {
return counter.get() >= queueCapacity;
}
@Override
public boolean isEmpty() {
return counter.get() == 0;
}
@Override
public int size() {
return counter.get();
}
@SneakyThrows
@Override
public boolean offer(Runnable r) {
if (isFullLoad()) {
boolean logged = false;
while (isFullLoad()) {
if (!logged) {
log.warn("Block caller thread until queue[{}/{}] polled then offer {}", counter.get(), queueCapacity, r);
logged = true;
}
synchronized (this) {
wait(500);
}
}
log.debug("Wait poll ok");
}
counter.incrementAndGet();
Task> task = pool.setTask(r);
if (task != null && task.flags.has(RunFlag.TRANSFER)) {
super.transfer(r);
return true;
}
return super.offer(r);
}
@Override
public Runnable poll(long timeout, TimeUnit unit) throws InterruptedException {
boolean ok = true;
try {
Runnable r = super.poll(timeout, unit);
ok = r != null;
return r;
} catch (InterruptedException e) {
ok = false;
throw e;
} finally {
if (ok) {
log.debug("Notify poll");
doNotify();
}
}
}
@Override
public Runnable take() throws InterruptedException {
try {
return super.take();
} finally {
log.debug("Notify take");
doNotify();
}
}
@Override
public boolean remove(Object o) {
boolean ok = super.remove(o);
if (ok) {
log.debug("Notify remove");
doNotify();
}
return ok;
}
private void doNotify() {
int c = counter.decrementAndGet();
synchronized (this) {
if (c < 0) {
counter.set(super.size());
TraceHandler.INSTANCE.saveMetric(Constants.MetricName.THREAD_QUEUE_SIZE_ERROR.name(),
String.format("FIX SIZE %s -> %s", c, counter));
}
notify();
}
}
}
static class Task implements Runnable, Callable, Supplier {
static Task adapt(Callable fn) {
Task t = as(fn);
return t != null ? t : new Task<>(fn::call, null, null);
}
static Task adapt(Runnable fn) {
Task t = as(fn);
return t != null ? t : new Task<>(() -> {
fn.run();
return null;
}, null, null);
}
static Task as(Object fn) {
return fn instanceof Task ? (Task) fn : null;
}
final Func fn;
final FlagsEnum flags;
final Object id;
final InternalThreadLocalMap parent;
final String traceId;
Task(Func fn, FlagsEnum flags, Object id) {
if (flags == null) {
flags = RunFlag.NONE.flags();
}
if (RxConfig.INSTANCE.threadPool.traceName != null) {
flags.add(RunFlag.THREAD_TRACE);
}
this.fn = fn;
this.flags = flags;
this.id = id;
parent = flags.has(RunFlag.INHERIT_FAST_THREAD_LOCALS) ? InternalThreadLocalMap.getIfSet() : null;
traceId = CTX_TRACE_ID.get();
}
@SneakyThrows
@Override
public T call() {
try {
return fn.invoke();
} catch (Throwable e) {
TraceHandler.INSTANCE.log(toString(), e);
throw e;
}
}
@Override
public void run() {
call();
}
@Override
public T get() {
return call();
}
@Override
public String toString() {
String hc = id != null ? id.toString() : Integer.toHexString(hashCode());
return String.format("Task-%s[%s]", hc, flags.getValue());
}
}
static class FutureTaskAdapter extends FutureTask {
final Task task;
public FutureTaskAdapter(Callable callable) {
super(callable);
task = Task.as(callable);
}
public FutureTaskAdapter(Runnable runnable, T result) {
super(runnable, result);
task = Task.as(runnable);
}
}
static class LockContext {
ReentrantLock lock;
AtomicInteger lockRefCnt;
}
@RequiredArgsConstructor
static class CompletableFutureWrapper extends CompletableFuture {
final Executor pool;
final boolean reuseOnUni;
CompletableFuture delegate;
CompletableFutureWrapper uniStage(CompletableFuture delegate) {
CompletableFutureWrapper wrapper = reuseOnUni
? (CompletableFutureWrapper) this
: new CompletableFutureWrapper<>(pool, false);
wrapper.delegate = delegate;
return wrapper;
}
Executor uniPool(Executor executor) {
// return ForkJoinPool.commonPool();
// return executor != null ? executor : pool;
return pool;
}
@Override
public CompletableFuture thenApply(Function super T, ? extends U> fn) {
return uniStage(delegate.thenApply(fn));
}
@Override
public CompletableFuture thenApplyAsync(Function super T, ? extends U> fn) {
return thenApplyAsync(fn, null);
}
@Override
public CompletableFuture thenApplyAsync(Function super T, ? extends U> fn, Executor executor) {
return uniStage(delegate.thenApplyAsync(fn, uniPool(executor)));
}
@Override
public CompletableFuture thenAccept(Consumer super T> action) {
return uniStage(delegate.thenAccept(action));
}
@Override
public CompletableFuture thenAcceptAsync(Consumer super T> action) {
return thenAcceptAsync(action, null);
}
@Override
public CompletableFuture thenAcceptAsync(Consumer super T> action, Executor executor) {
return uniStage(delegate.thenAcceptAsync(action, uniPool(executor)));
}
@Override
public CompletableFuture thenRun(Runnable action) {
return uniStage(delegate.thenRun(action));
}
@Override
public CompletableFuture thenRunAsync(Runnable action) {
return thenRunAsync(action, null);
}
@Override
public CompletableFuture thenRunAsync(Runnable action, Executor executor) {
return uniStage(delegate.thenRunAsync(action, uniPool(executor)));
}
@Override
public CompletableFuture thenCombine(CompletionStage extends U> other, BiFunction super T, ? super U, ? extends V> fn) {
return uniStage(delegate.thenCombine(other, fn));
}
@Override
public CompletableFuture thenCombineAsync(CompletionStage extends U> other, BiFunction super T, ? super U, ? extends V> fn) {
return thenCombineAsync(other, fn, null);
}
@Override
public CompletableFuture thenCombineAsync(CompletionStage extends U> other, BiFunction super T, ? super U, ? extends V> fn, Executor executor) {
return uniStage(delegate.thenCombineAsync(other, fn, uniPool(executor)));
}
@Override
public CompletableFuture thenAcceptBoth(CompletionStage extends U> other, BiConsumer super T, ? super U> action) {
return uniStage(delegate.thenAcceptBoth(other, action));
}
@Override
public CompletableFuture thenAcceptBothAsync(CompletionStage extends U> other, BiConsumer super T, ? super U> action) {
return thenAcceptBothAsync(other, action, null);
}
@Override
public CompletableFuture thenAcceptBothAsync(CompletionStage extends U> other, BiConsumer super T, ? super U> action, Executor executor) {
return uniStage(delegate.thenAcceptBothAsync(other, action, uniPool(executor)));
}
@Override
public CompletableFuture runAfterBoth(CompletionStage> other, Runnable action) {
return uniStage(delegate.runAfterBoth(other, action));
}
@Override
public CompletableFuture runAfterBothAsync(CompletionStage> other, Runnable action) {
return runAfterBothAsync(other, action, null);
}
@Override
public CompletableFuture runAfterBothAsync(CompletionStage> other, Runnable action, Executor executor) {
return uniStage(delegate.runAfterBothAsync(other, action, uniPool(executor)));
}
@Override
public CompletableFuture applyToEither(CompletionStage extends T> other, Function super T, U> fn) {
return uniStage(delegate.applyToEither(other, fn));
}
@Override
public CompletableFuture applyToEitherAsync(CompletionStage extends T> other, Function super T, U> fn) {
return applyToEitherAsync(other, fn, null);
}
@Override
public CompletableFuture applyToEitherAsync(CompletionStage extends T> other, Function super T, U> fn, Executor executor) {
return uniStage(delegate.applyToEitherAsync(other, fn, uniPool(executor)));
}
@Override
public CompletableFuture acceptEither(CompletionStage extends T> other, Consumer super T> action) {
return uniStage(delegate.acceptEither(other, action));
}
@Override
public CompletableFuture acceptEitherAsync(CompletionStage extends T> other, Consumer super T> action) {
return acceptEitherAsync(other, action, null);
}
@Override
public CompletableFuture acceptEitherAsync(CompletionStage extends T> other, Consumer super T> action, Executor executor) {
return uniStage(delegate.acceptEitherAsync(other, action, uniPool(executor)));
}
@Override
public CompletableFuture runAfterEither(CompletionStage> other, Runnable action) {
return uniStage(delegate.runAfterEither(other, action));
}
@Override
public CompletableFuture runAfterEitherAsync(CompletionStage> other, Runnable action) {
return runAfterEitherAsync(other, action, null);
}
@Override
public CompletableFuture runAfterEitherAsync(CompletionStage> other, Runnable action, Executor executor) {
return uniStage(delegate.runAfterEitherAsync(other, action, uniPool(executor)));
}
@Override
public CompletableFuture thenCompose(Function super T, ? extends CompletionStage> fn) {
return uniStage(delegate.thenCompose(fn));
}
@Override
public CompletableFuture thenComposeAsync(Function super T, ? extends CompletionStage> fn) {
return thenComposeAsync(fn, null);
}
@Override
public CompletableFuture thenComposeAsync(Function super T, ? extends CompletionStage> fn, Executor executor) {
return uniStage(delegate.thenComposeAsync(fn, uniPool(executor)));
}
@Override
public CompletableFuture whenComplete(BiConsumer super T, ? super Throwable> action) {
return uniStage(delegate.whenComplete(action));
}
@Override
public CompletableFuture whenCompleteAsync(BiConsumer super T, ? super Throwable> action) {
return whenCompleteAsync(action, null);
}
@Override
public CompletableFuture whenCompleteAsync(BiConsumer super T, ? super Throwable> action, Executor executor) {
return uniStage(delegate.whenCompleteAsync(action, uniPool(executor)));
}
@Override
public CompletableFuture handle(BiFunction super T, Throwable, ? extends U> fn) {
return uniStage(delegate.handle(fn));
}
@Override
public CompletableFuture handleAsync(BiFunction super T, Throwable, ? extends U> fn) {
return handleAsync(fn, null);
}
@Override
public CompletableFuture handleAsync(BiFunction super T, Throwable, ? extends U> fn, Executor executor) {
return uniStage(delegate.handleAsync(fn, uniPool(executor)));
}
@Override
public CompletableFuture toCompletableFuture() {
return uniStage(delegate.toCompletableFuture());
}
@Override
public CompletableFuture exceptionally(Function fn) {
return uniStage(delegate.exceptionally(fn));
}
//region ignore
@Override
public boolean isDone() {
return delegate.isDone();
}
@Override
public T get() throws InterruptedException, ExecutionException {
return delegate.get();
}
@Override
public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
return delegate.get(timeout, unit);
}
@Override
public T join() {
return delegate.join();
}
@Override
public T getNow(T valueIfAbsent) {
return delegate.getNow(valueIfAbsent);
}
@Override
public boolean complete(T value) {
return delegate.complete(value);
}
@Override
public boolean completeExceptionally(Throwable ex) {
return delegate.completeExceptionally(ex);
}
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
return delegate.cancel(mayInterruptIfRunning);
}
@Override
public boolean isCancelled() {
return delegate.isCancelled();
}
@Override
public boolean isCompletedExceptionally() {
return delegate.isCompletedExceptionally();
}
@Override
public void obtrudeValue(T value) {
delegate.obtrudeValue(value);
}
@Override
public void obtrudeException(Throwable ex) {
delegate.obtrudeException(ex);
}
@Override
public int getNumberOfDependents() {
return delegate.getNumberOfDependents();
}
@Override
public String toString() {
return delegate.toString();
}
//endregion
}
static class DynamicSizer implements TimerTask {
final Map> hold = new WeakIdentityMap<>(8);
DynamicSizer() {
timer.newTimeout(this, RxConfig.INSTANCE.threadPool.samplingPeriod, TimeUnit.MILLISECONDS);
}
@Override
public void run(Timeout timeout) throws Exception {
try {
Decimal cpuLoad = Decimal.valueOf(Sys.osMx.getSystemCpuLoad() * 100);
for (Map.Entry> entry : hold.entrySet()) {
ThreadPoolExecutor pool = entry.getKey();
if (pool instanceof ScheduledExecutorService) {
scheduledThread(cpuLoad, pool, entry.getValue());
continue;
}
thread(cpuLoad, pool, entry.getValue());
}
} finally {
timer.newTimeout(this, RxConfig.INSTANCE.threadPool.samplingPeriod, TimeUnit.MILLISECONDS);
}
}
private void thread(Decimal cpuLoad, ThreadPoolExecutor pool, BiTuple tuple) {
IntWaterMark waterMark = tuple.left;
int decrementCounter = tuple.middle;
int incrementCounter = tuple.right;
String prefix = pool.toString();
if (log.isDebugEnabled()) {
log.debug("{} PoolSize={}+[{}] Threshold={}[{}-{}]% de/incrementCounter={}/{}", prefix,
pool.getPoolSize(), pool.getQueue().size(),
cpuLoad, waterMark.getLow(), waterMark.getHigh(), decrementCounter, incrementCounter);
}
if (cpuLoad.gt(waterMark.getHigh())) {
if (++decrementCounter >= RxConfig.INSTANCE.threadPool.samplingTimes) {
log.info("{} PoolSize={}+[{}] Threshold={}[{}-{}]% decrement to {}", prefix,
pool.getPoolSize(), pool.getQueue().size(),
cpuLoad, waterMark.getLow(), waterMark.getHigh(), decrSize(pool));
decrementCounter = 0;
}
} else {
decrementCounter = 0;
}
if (!pool.getQueue().isEmpty() && cpuLoad.lt(waterMark.getLow())) {
if (++incrementCounter >= RxConfig.INSTANCE.threadPool.samplingTimes) {
log.info("{} PoolSize={}+[{}] Threshold={}[{}-{}]% increment to {}", prefix,
pool.getPoolSize(), pool.getQueue().size(),
cpuLoad, waterMark.getLow(), waterMark.getHigh(), incrSize(pool));
incrementCounter = 0;
}
} else {
incrementCounter = 0;
}
tuple.middle = decrementCounter;
tuple.right = incrementCounter;
}
private void scheduledThread(Decimal cpuLoad, ThreadPoolExecutor pool, BiTuple tuple) {
IntWaterMark waterMark = tuple.left;
int decrementCounter = tuple.middle;
int incrementCounter = tuple.right;
String prefix = pool.toString();
int active = pool.getActiveCount();
int size = pool.getCorePoolSize();
float idle = (float) active / size * 100;
log.debug("{} PoolSize={} QueueSize={} Threshold={}[{}-{}]% idle={} de/incrementCounter={}/{}", prefix,
pool.getCorePoolSize(), pool.getQueue().size(),
cpuLoad, waterMark.getLow(), waterMark.getHigh(), 100 - idle, decrementCounter, incrementCounter);
RxConfig.ThreadPoolConfig conf = RxConfig.INSTANCE.threadPool;
if (size > conf.minDynamicSize && (idle <= waterMark.getHigh() || cpuLoad.gt(waterMark.getHigh()))) {
if (++decrementCounter >= conf.samplingTimes) {
log.info("{} Threshold={}[{}-{}]% idle={} decrement to {}", prefix,
cpuLoad, waterMark.getLow(), waterMark.getHigh(), 100 - idle, decrSize(pool));
decrementCounter = 0;
}
} else {
decrementCounter = 0;
}
if (active >= size && cpuLoad.lt(waterMark.getLow())) {
if (++incrementCounter >= conf.samplingTimes) {
log.info("{} Threshold={}[{}-{}]% increment to {}", prefix,
cpuLoad, waterMark.getLow(), waterMark.getHigh(), incrSize(pool));
incrementCounter = 0;
}
} else {
incrementCounter = 0;
}
tuple.middle = decrementCounter;
tuple.right = incrementCounter;
}
public void register(ThreadPoolExecutor pool, IntWaterMark cpuWaterMark) {
if (cpuWaterMark == null) {
return;
}
hold.put(pool, BiTuple.of(cpuWaterMark, 0, 0));
}
}
//region static members
public static volatile Func traceIdGenerator;
public static volatile BiAction traceIdChanger;
static final ThreadLocal> CTX_PARENT_TRACE_ID = new InheritableThreadLocal<>();
static final ThreadLocal CTX_TRACE_ID = new InheritableThreadLocal<>();
static final FastThreadLocal ASYNC_CONTINUE = new FastThreadLocal<>();
static final FastThreadLocal
© 2015 - 2025 Weber Informatics LLC | Privacy Policy