v1.5.1-SNAPSHOT 1.rebase 2.重构不良代码 3.更新QuickStart.md 4.分模块 5.使用任务句柄OnceWork 6.增加任务取消功能

This commit is contained in:
TcSnZh
2021-05-13 00:24:44 +08:00
committed by TcSnZh
parent 787abdb6f1
commit 46f76f6bf8
94 changed files with 6626 additions and 1830 deletions

40
.gitignore vendored
View File

@@ -1,32 +1,32 @@
HELP.md
target/
**/HELP.md
**/target/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**
!**/src/test/**
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
**/.apt_generated
**/.classpath
**/.factorypath
**/.project
**/.settings
**/.springBeans
**/.sts4-cache
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
**/.idea
**/*.iws
**/*.iml
**/*.ipr
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
build/
**/nbproject/private/
**/nbbuild/
**/dist/
**/nbdist/
**/.nb-gradle/
**/build/
### VS Code ###
.vscode/
**/.vscode/

File diff suppressed because it is too large Load Diff

View File

@@ -89,8 +89,16 @@
在V1.3后框架支持在worker的action的入参Map<String, WorkerWrapper>中获取任意一个执行单元的执行结果当然可以取其中的1个、多个执行结果作为自己的入参。Key就是在定义wrapper时通过id传进来的唯一id标识。详情demo可以查看test包下dependnew包案例。
## 并发场景可能存在的需求之——全组任务的超时
一组任务虽然内部的各个执行单元的时间不可控但是我可以控制全组的执行时间不超过某个值。通过设置timeOut来控制全组的执行阈值。
## 并发场景可能存在的需求之——任务的超时
> 在v1.4中:
>
> 一组任务虽然内部的各个执行单元的时间不可控但是我可以控制全组的执行时间不超过某个值。通过设置timeOut来控制全组的执行阈值。
在v1.5中:
每个wrapper可以设置自己的超时时间同时也可以设置整组任务的超时时间。
且可以设置一旦超时则打断线程(默认不启用打断线程)
## 并发场景可能存在的需求之——高性能、低线程数
该框架全程无锁,不依靠线程锁来保证顺序。
@@ -114,4 +122,3 @@
## 快速开始
[点此开启实战](https://gitee.com/jd-platform-opensource/asyncTool/blob/master/QuickStart.md)

27
asyncTool-core/pom.xml Normal file
View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>asyncTool</artifactId>
<groupId>com.jd.platform</groupId>
<version>1.5.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>asyncTool-core</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.jd.platform</groupId>
<artifactId>asyncTool-openutil</artifactId>
<version>1.5.1-SNAPSHOT</version>
</dependency>
</dependencies>
</project>

View File

@@ -15,14 +15,10 @@ public class DefaultCallback<T, V> implements ICallback<T, V> {
}
/**
* 默认将打印存在的非{@link com.jd.platform.async.exception.SkippedException}的异常
* 默认情况啥回调都没有而且将吞掉所有异常显示只保存在{@link WorkResult}
*/
@Override
public void result(boolean success, T param, WorkResult<V> workResult) {
Exception ex = workResult.getEx();
if (ex != null && !(ex instanceof SkippedException)) {
ex.printStackTrace();
}
// do nothing
}
}

View File

@@ -0,0 +1,46 @@
package com.jd.platform.async.callback;
import com.jd.platform.async.exception.SkippedException;
import com.jd.platform.async.worker.WorkResult;
/**
* 每个执行单元执行完毕后,会回调该接口</p>
* 需要监听执行结果的,实现该接口即可
*
* @author wuweifeng wrote on 2019-11-19.
*/
@FunctionalInterface
public interface ICallback<T, V> {
/**
* 任务开始的监听
*/
default void begin() {
}
/**
* 耗时操作执行完毕后就给value注入值
* <p/>
* 只要Wrapper被调用后成功或失败/超时,该方法都会被执行。
*/
void result(boolean success, T param, WorkResult<V> workResult);
/**
* 提供常量选项:打印异常信息,跳过时的异常{@link SkippedException}不会打印。
*/
ICallback PRINT_EXCEPTION_STACK_TRACE = new ICallback<Object, Object>() {
@Override
public void result(boolean success, Object param, WorkResult<Object> workResult) {
Exception ex = workResult.getEx();
if (ex != null && !(ex instanceof SkippedException)) {
ex.printStackTrace();
}
}
@Override
public String toString() {
return "PRINT_EXCEPTION_STACK_TRACE";
}
};
}

View File

@@ -1,9 +1,9 @@
package com.jd.platform.async.callback;
import java.util.Map;
import com.jd.platform.async.wrapper.WorkerWrapper;
import java.util.Map;
/**
* 每个最小执行单元需要实现该接口
*
@@ -17,10 +17,10 @@ public interface IWorker<T, V> {
* @param object object
* @param allWrappers 任务包装
*/
V action(T object, Map<String, WorkerWrapper> allWrappers);
V action(T object, Map<String, WorkerWrapper<?,?>> allWrappers);
/**
* 超时异常时返回的默认值
* 超时异常跳过返回的默认值
*
* @return 默认值
*/

View File

@@ -0,0 +1,19 @@
package com.jd.platform.async.exception;
/**
* 整组取消,设置该异常。
*
* @author tcsnzh[zh.jobs@foxmail.com] create this in 2021/5/25-下午6:12
*/
public class CancelSkippedException extends SkippedException {
public CancelSkippedException() {
}
public CancelSkippedException(String message) {
super(message);
}
public CancelSkippedException(String message, long skipAt) {
super(message, skipAt);
}
}

View File

@@ -1,16 +1,30 @@
package com.jd.platform.async.exception;
import com.jd.platform.async.executor.timer.SystemClock;
/**
* 如果任务在执行之前自己后面的任务已经执行完或正在被执行则抛该exception
*
* @author wuweifeng wrote on 2020-02-18
* @version 1.0
*/
public class SkippedException extends RuntimeException {
private final long skipAt;
public SkippedException() {
super();
this(null);
}
public SkippedException(String message) {
this(message, SystemClock.now());
}
public SkippedException(String message, long skipAt) {
super(message);
this.skipAt = skipAt;
}
public long getSkipAt() {
return skipAt;
}
}

View File

@@ -4,12 +4,15 @@ package com.jd.platform.async.executor;
import com.jd.platform.async.callback.DefaultGroupCallback;
import com.jd.platform.async.callback.IGroupCallback;
import com.jd.platform.async.executor.timer.SystemClock;
import com.jd.platform.async.worker.OnceWork;
import com.jd.platform.async.wrapper.WorkerWrapper;
import com.jd.platform.async.wrapper.WrapperEndingInspector;
import com.jd.platform.async.wrapper.WorkerWrapperGroup;
import com.sun.istack.internal.Nullable;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
/**
@@ -23,61 +26,90 @@ public class Async {
// ========================= 任务执行核心代码 =========================
/**
* 出发点
*
* @return 只要执行未超时就返回true
* {@link #work(long, ExecutorService, Collection, String)}方法的简易封装
* 使用uuid作为工作id使用{@link #getCommonPool()}作为线程池
*/
public static boolean beginWork(long timeout,
ExecutorService executorService,
Collection<? extends WorkerWrapper<?,?>> workerWrappers)
throws InterruptedException {
if (workerWrappers == null || workerWrappers.size() == 0) {
return false;
public static OnceWork work(long timeout,
Collection<? extends WorkerWrapper<?, ?>> workerWrappers) {
return work(timeout, getCommonPool(), workerWrappers);
}
/**
* {@link #work(long, ExecutorService, Collection, String)}方法的简易封装
* 可变参式传入使用uuid作为工作id使用{@link #getCommonPool()}作为线程池
*/
public static OnceWork work(long timeout,
WorkerWrapper<?, ?>... workerWrappers) {
return work(timeout, getCommonPool(), workerWrappers);
}
/**
* {@link #work(long, ExecutorService, Collection, String)}方法的简易封装
* 可变参式传入使用uuid作为工作id
*/
public static OnceWork work(long timeout,
ExecutorService executorService,
WorkerWrapper<?, ?>... workerWrappers) {
return work(timeout, executorService, Arrays.asList(
Objects.requireNonNull(workerWrappers, "workerWrappers array is null")));
}
/**
* {@link #work(long, ExecutorService, Collection, String)}方法的简易封装
* 省略工作id使用uuid
*/
public static OnceWork work(long timeout,
ExecutorService executorService,
Collection<? extends WorkerWrapper<?, ?>> workerWrappers) {
return work(timeout, executorService, workerWrappers, UUID.randomUUID().toString());
}
/**
* 核心方法
* 该方法不是同步阻塞执行的如果想要同步阻塞执行则调用返回值的{@link OnceWork#awaitFinish()}即可
*
* @param timeout 全组超时时间
* @param executorService 执行线程池
* @param workerWrappers 任务容器集合
* @param workId 本次工作id
* @return 返回 {@link OnceWork}封装对象
*/
public static OnceWork work(long timeout,
ExecutorService executorService,
Collection<? extends WorkerWrapper<?, ?>> workerWrappers,
String workId) {
if (workerWrappers == null || workerWrappers.isEmpty()) {
return OnceWork.emptyWork(workId);
}
//保存上次执行的线程池变量为了兼容以前的旧功能
Async.lastExecutorService = Objects.requireNonNull(executorService, "ExecutorService is null ! ");
//定义一个map存放所有的wrapperkey为wrapper的唯一idvalue是该wrapper可以从value中获取wrapper的result
final ConcurrentMap<String, WorkerWrapper<?,?>> forParamUseWrappers =
new ConcurrentHashMap<>(Math.max(workerWrappers.size() * 3, 8));
final WrapperEndingInspector inspector = new WrapperEndingInspector(SystemClock.now() + timeout);
inspector.addWrapper(workerWrappers);
Async.lastExecutorService.set(Objects.requireNonNull(executorService, "ExecutorService is null ! "));
final WorkerWrapperGroup group = new WorkerWrapperGroup(SystemClock.now(), timeout);
final OnceWork.Impl onceWork = new OnceWork.Impl(group, workId);
group.addWrapper(workerWrappers);
workerWrappers.forEach(wrapper -> {
if (wrapper == null) {
return;
}
executorService.submit(() -> wrapper.work(executorService, timeout, forParamUseWrappers, inspector));
executorService.submit(() -> wrapper.work(executorService, timeout, group));
});
inspector.registerToPollingCenter();
return inspector.await();
//处理超时的逻辑被移动到了WrapperEndingInspector中
return onceWork;
}
/**
* 如果想自定义线程池请传pool不自定义的话就走默认的COMMON_POOL
* @deprecated 已经被 {@link #work(long, ExecutorService, Collection, String)}方法取代
*/
public static boolean beginWork(long timeout, ExecutorService executorService, WorkerWrapper... workerWrapper)
throws ExecutionException, InterruptedException {
if (workerWrapper == null || workerWrapper.length == 0) {
return false;
}
Set workerWrappers = Arrays.stream(workerWrapper).collect(Collectors.toSet());
return beginWork(timeout, executorService, workerWrappers);
}
/**
* 同步阻塞,直到所有都完成,或失败
*/
public static boolean beginWork(long timeout, WorkerWrapper... workerWrapper) throws ExecutionException, InterruptedException {
return beginWork(timeout, getCommonPool(), workerWrapper);
}
@SuppressWarnings("unused")
@Deprecated
public static void beginWorkAsync(long timeout, IGroupCallback groupCallback, WorkerWrapper... workerWrapper) {
beginWorkAsync(timeout, getCommonPool(), groupCallback, workerWrapper);
}
/**
* 异步执行,直到所有都完成,或失败后发起回调
*
* @deprecated 已经被 {@link #work(long, ExecutorService, Collection, String)}方法取代
*/
@Deprecated
public static void beginWorkAsync(long timeout, ExecutorService executorService, IGroupCallback groupCallback, WorkerWrapper... workerWrapper) {
if (groupCallback == null) {
groupCallback = new DefaultGroupCallback();
@@ -128,7 +160,7 @@ public class Async {
* 该线程池将会给线程取名为asyncTool-commonPool-thread-0数字不重复
* </p>
*/
private static ThreadPoolExecutor COMMON_POOL;
private static volatile ThreadPoolExecutor COMMON_POOL;
/**
* 在以前及现在的版本中
@@ -136,8 +168,11 @@ public class Async {
* <p/>
* 注意这里是个static也就是只能有一个线程池用户自定义线程池时也只能定义一个
*/
private static volatile ExecutorService lastExecutorService;
private static final AtomicReference<ExecutorService> lastExecutorService = new AtomicReference<>(null);
/**
* 该方法将会返回{@link #COMMON_POOL}如果还未初始化则会懒加载初始化后再返回
*/
public static ThreadPoolExecutor getCommonPool() {
if (COMMON_POOL == null) {
synchronized (Async.class) {
@@ -151,9 +186,11 @@ public class Async {
new ThreadFactory() {
private final AtomicLong threadCount = new AtomicLong(0);
@SuppressWarnings("NullableProblems")
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r, "asyncTool-commonPool-thread-" + threadCount.getAndIncrement());
Thread t = new Thread(r,
"asyncTool-commonPool-thread-" + threadCount.getAndIncrement());
t.setDaemon(true);
return t;
}
@@ -181,7 +218,15 @@ public class Async {
",largestCount=" + COMMON_POOL.getLargestPoolSize();
}
public static synchronized void shutDownCommonPool(boolean now) {
/**
* @param now 是否立即关闭
* @return 如果尚未调用过{@link #getCommonPool()}即没有初始化默认线程池返回false否则返回true
*/
@SuppressWarnings("unused")
public static synchronized boolean shutDownCommonPool(boolean now) {
if (COMMON_POOL == null) {
return false;
}
if (!COMMON_POOL.isShutdown()) {
if (now) {
COMMON_POOL.shutdownNow();
@@ -189,6 +234,52 @@ public class Async {
COMMON_POOL.shutdown();
}
}
return true;
}
// ========================= deprecated =========================
/**
* 同步执行一次任务
*
* @return 只要执行未超时就返回true
* @deprecated 已经被 {@link #work(long, ExecutorService, Collection, String)}方法取代
*/
@Deprecated
public static boolean beginWork(long timeout,
ExecutorService executorService,
Collection<? extends WorkerWrapper<?, ?>> workerWrappers)
throws InterruptedException {
final OnceWork work = work(timeout, executorService, workerWrappers);
work.awaitFinish();
return work.hasTimeout();
}
/**
* 同步执行一次任务
* 如果想自定义线程池请传pool不自定义的话就走默认的COMMON_POOL
*
* @deprecated 已经被 {@link #work(long, ExecutorService, Collection, String)}方法取代
*/
@Deprecated
public static boolean beginWork(long timeout, ExecutorService executorService, WorkerWrapper... workerWrapper)
throws ExecutionException, InterruptedException {
if (workerWrapper == null || workerWrapper.length == 0) {
return false;
}
Set workerWrappers = Arrays.stream(workerWrapper).collect(Collectors.toSet());
//noinspection unchecked
return beginWork(timeout, executorService, workerWrappers);
}
/**
* 同步阻塞,直到所有都完成,或失败
*
* @deprecated 已经被 {@link #work(long, ExecutorService, Collection, String)}方法取代
*/
@Deprecated
public static boolean beginWork(long timeout, WorkerWrapper... workerWrapper) throws ExecutionException, InterruptedException {
return beginWork(timeout, getCommonPool(), workerWrapper);
}
/**
@@ -202,8 +293,9 @@ public class Async {
*/
@Deprecated
public static void shutDown() {
if (lastExecutorService != COMMON_POOL) {
shutDown(lastExecutorService);
final ExecutorService last = lastExecutorService.get();
if (last != COMMON_POOL) {
shutDown(last);
}
}
@@ -214,7 +306,7 @@ public class Async {
* @deprecated 没啥用的方法要关闭线程池还不如直接调用线程池的关闭方法避免歧义
*/
@Deprecated
public static void shutDown(ExecutorService executorService) {
public static void shutDown(@Nullable ExecutorService executorService) {
if (executorService != null) {
executorService.shutdown();
}

View File

@@ -0,0 +1,87 @@
package com.jd.platform.async.executor;
import com.jd.platform.async.openutil.timer.HashedWheelTimer;
import com.jd.platform.async.openutil.timer.Timeout;
import com.jd.platform.async.openutil.timer.Timer;
import com.jd.platform.async.openutil.timer.TimerTask;
import com.jd.platform.async.wrapper.WorkerWrapperGroup;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
/**
* 检查{@link WorkerWrapperGroup}是否调用完成的轮询中心。
* 内部使用时间轮进行轮询。
* <p>
* ===========================================================================================
* <p>
* 在v1.4及以前的版本,存在如下问题:
* >
* 在使用线程数量较少的线程池进行beginWork时调用WorkerWrapper#beginNext方法时
* 会因为本线程等待下游Wrapper执行完成而存在线程耗尽bug。线程池会死翘翘的僵住、动弹不得。
* >
* 例如仅有2个线程的线程池执行以下任务
* {@code
* <p>
* 这是旧版本(v1.4及以前)中可能会引发线程耗尽bug的情况在test/v15.wrappertest中示例testThreadPolling_V14Bug说明了这个bug
* 线程数2
* A(5ms)--B1(10ms) ---|--> C1(5ms)
* . \ | (B1、B2任一完成可执行C1、C2)
* . ---> B2(20ms) --|--> C2(5ms)
* <p>
* }
* 线程1执行了A然后在{@link CompletableFuture#allOf(CompletableFuture[])}等待B1与B2执行完成。
* 线程2执行了B1或B2中的一个也在allOf方法等待C1、C2完成。
* 结果没有线程执行C和B2了导致超时而死并且这个线程池线程有可能被耗尽。
* >
*
* @author create by TcSnZh on 2021/5/9-下午9:22
*/
public class PollingCenter {
// ========== singleton instance ==========
private static final PollingCenter instance = new PollingCenter();
public static PollingCenter getInstance() {
return instance;
}
// ========== fields and methods ==========
public void checkGroup(WorkerWrapperGroup.CheckFinishTask task) {
checkGroup(task, 0);
}
public void checkGroup(WorkerWrapperGroup.CheckFinishTask task, long daley) {
timer.newTimeout(task, daley, TimeUnit.MILLISECONDS);
}
private final Timer timer = new Timer() {
private final HashedWheelTimer hashedWheelTimer = new HashedWheelTimer(
r -> {
Thread thread = new Thread(r, "asyncTool-pollingThread");
thread.setDaemon(true);
return thread;
},
1,
TimeUnit.MILLISECONDS,
1024);
@Override
public Timeout newTimeout(TimerTask task, long delay, TimeUnit unit) {
return hashedWheelTimer.newTimeout(task, delay, unit);
}
@Override
public Set<? extends Timeout> stop() {
return hashedWheelTimer.stop();
}
@Override
public String toString() {
return "PollingCenter.timer";
}
};
}

View File

@@ -2,7 +2,6 @@ package com.jd.platform.async.executor.timer;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

View File

@@ -0,0 +1,375 @@
package com.jd.platform.async.worker;
import com.jd.platform.async.executor.timer.SystemClock;
import com.jd.platform.async.wrapper.WorkerWrapper;
import com.jd.platform.async.wrapper.WorkerWrapperGroup;
import java.util.*;
import java.util.concurrent.*;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* 一次工作结果的总接口。
*
* @author tcsnzh[zh.jobs@foxmail.com] create this in 2021/5/25-下午3:22
*/
public interface OnceWork {
/**
* 返回唯一的workId
*/
String workId();
/**
* 判断是否结束。因超时而结束也算结束。
*/
boolean isFinish();
/**
* 同步等待到结束。
*/
void awaitFinish() throws InterruptedException;
/**
* 判断是否超时
*
* @return 如果尚未结束或已结束但未超时返回false。已结束且已经超时返回true。
*/
boolean hasTimeout();
/**
* 判断是否全部wrapper都处于 执行成功 或 跳过。
*
* @return 如果已经结束所有wrapper都成功或跳过返回true否则返回false。如果尚未结束返回false。
*/
default boolean allSuccess() {
if (!isFinish()) {
return false;
}
return getWrappers().values().stream().allMatch(wrapper -> {
final ResultState state = wrapper.getWorkResult().getResultState();
return state == ResultState.SUCCESS || state == ResultState.DEFAULT;
});
}
/**
* 获取全部参与到工作中的wrapper。
*/
Map<String, WorkerWrapper<?, ?>> getWrappers();
/**
* 获取{@link WorkResult#getResultState()}为{@link ResultState#SUCCESS}的wrapper。
*/
default Map<String, WorkerWrapper<?, ?>> getSuccessWrappers() {
return getWrappersOfState(ResultState.SUCCESS);
}
/**
* 获取状态于这些state中的wrapper。
*
* @param ofState 状态列表
* @return 返回Map
*/
default Map<String, WorkerWrapper<?, ?>> getWrappersOfState(ResultState... ofState) {
final HashSet<ResultState> states = new HashSet<>(Arrays.asList(ofState));
return getWrappers().entrySet().stream()
.filter(entry -> states.contains(entry.getValue().getWorkResult().getResultState()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
/**
* 获取启动时间
*/
long getStartTime();
/**
* 获取结束时间
*
* @return 如果超时,返回超时的时刻。如果尚未结束,则抛出异常。
* @throws IllegalStateException 尚未结束,抛出异常。
*/
long getFinishTime();
/**
* @return 已经取消完成
*/
boolean isCancelled();
/**
* @return 是否正在取消中
*/
boolean isWaitingCancel();
/**
* 请求异步取消。
*/
void pleaseCancel();
/**
* 同步等待取消完成。
*/
default void pleaseCancelAndAwaitFinish() throws InterruptedException {
if (!isCancelled() && !isWaitingCancel()) {
pleaseCancel();
}
awaitFinish();
}
/**
* @return 返回 {@link AsFuture}封装对象。
*/
default AsFuture asFuture() {
return new AsFuture(this, limitTime -> limitTime / 16);
}
/**
* @param sleepCheckInterval 为防止线程爆炸,在{@link Future#get(long, TimeUnit)}方法时使用隔一段时间检查一次。
* 该Function的参数为总超时毫秒值返回值为检查时间间隔。
* @return 返回 {@link AsFuture}封装对象。
*/
default AsFuture asFuture(Function<Long, Long> sleepCheckInterval) {
return new AsFuture(this, sleepCheckInterval);
}
// static
/**
* 空任务
*/
static OnceWork emptyWork(String workId) {
return new EmptyWork(workId);
}
// class
class AsFuture implements Future<Map<String, WorkerWrapper<?, ?>>> {
private final OnceWork onceWork;
private final Function<Long, Long> sleepCheckInterval;
private AsFuture(OnceWork onceWork, Function<Long, Long> sleepCheckInterval) {
this.onceWork = onceWork;
this.sleepCheckInterval = sleepCheckInterval;
}
/**
* 同步等待取消
*
* @param ignore__mayInterruptIfRunning 该参数将被无视。因为暂未实现“修改允许打断属性”功能。 // todo 等待实现
*/
@Override
public boolean cancel(boolean ignore__mayInterruptIfRunning) {
try {
onceWork.pleaseCancelAndAwaitFinish();
} catch (InterruptedException e) {
throw new RuntimeException("", e);
}
return true;
}
@Override
public boolean isCancelled() {
return onceWork.isCancelled();
}
@Override
public boolean isDone() {
return onceWork.isFinish();
}
@Override
public Map<String, WorkerWrapper<?, ?>> get() throws InterruptedException, ExecutionException {
if (!onceWork.isFinish()) {
onceWork.awaitFinish();
}
return onceWork.getWrappers();
}
/**
* 避免线程爆炸,该方法不予单独开线程,而是单线程{@link Thread#sleep(long)}每睡一段时间检查一次。
*/
@Override
public Map<String, WorkerWrapper<?, ?>> get(long timeout,
@SuppressWarnings("NullableProblems") TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
final long millis = Objects.requireNonNull(unit).toMillis(timeout);
final long interval = Math.max(1, Math.min(millis, sleepCheckInterval.apply(millis)));
for (int i = 0; interval * i < millis; i++) {
if (onceWork.isFinish()) {
return onceWork.getWrappers();
}
Thread.sleep(interval);
}
throw new TimeoutException(
"onceWork.asFuture.get(long,TimeUnit) out of time limit(" +
timeout + "," + unit + ") , this is " + this);
}
@Override
public String toString() {
return "(asFuture from " + this + ")";
}
}
abstract class AbstractOnceWork implements OnceWork {
protected final String workId;
public AbstractOnceWork(String workId) {
this.workId = workId;
}
@Override
public String workId() {
return workId;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof OnceWork)) {
return false;
}
OnceWork _o = (OnceWork) o;
return Objects.equals(_o.workId(), this.workId());
}
@Override
public int hashCode() {
return workId().hashCode();
}
@Override
public String toString() {
final boolean finish;
final StringBuilder sb = new StringBuilder(48)
.append(this.getClass().getSimpleName())
.append("{isFinish=").append(finish = isFinish())
.append(", hasTimeout=").append(hasTimeout())
.append(", allSuccess=").append(allSuccess())
.append(", getStartTime=").append(getStartTime())
.append(", isCancelled=").append(isCancelled())
.append(", isWaitingCancel=").append(isWaitingCancel());
if (finish) {
sb.append(", getFinishTime=").append(getFinishTime());
}
return sb
.append(", wrappers::getId=").append(getWrappers().keySet())
.append('}').toString();
}
}
class Impl extends AbstractOnceWork {
protected final WorkerWrapperGroup group;
public Impl(WorkerWrapperGroup group, String workId) {
super(workId);
this.group = group;
}
@Override
public boolean isFinish() {
return group.getEndCDL().getCount() > 0;
}
@Override
public void awaitFinish() throws InterruptedException {
group.getEndCDL().await();
}
@Override
public boolean hasTimeout() {
return group.getAnyTimeout().get();
}
@Override
public Map<String, WorkerWrapper<?, ?>> getWrappers() {
return group.getForParamUseWrappers();
}
@Override
public long getStartTime() {
return group.getGroupStartTime();
}
@Override
public long getFinishTime() {
if (isFinish()) {
throw new IllegalStateException("work not finish.");
}
return group.getFinishTime();
}
@Override
public boolean isCancelled() {
return group.isCancelled();
}
@Override
public boolean isWaitingCancel() {
return group.isWaitingCancel();
}
@Override
public void pleaseCancel() {
group.pleaseCancel();
}
}
class EmptyWork extends AbstractOnceWork {
private final long initTime = SystemClock.now();
public EmptyWork(String workId) {
super(workId);
}
@Override
public boolean isFinish() {
return true;
}
@Override
public void awaitFinish() {
// do nothing
}
@Override
public boolean hasTimeout() {
return false;
}
@Override
public Map<String, WorkerWrapper<?, ?>> getWrappers() {
return Collections.emptyMap();
}
@Override
public long getStartTime() {
return initTime;
}
@Override
public long getFinishTime() {
return initTime;
}
@Override
public boolean isCancelled() {
return false;
}
@Override
public boolean isWaitingCancel() {
return false;
}
@Override
public void pleaseCancel() {
}
@Override
public String toString() {
return "(it's empty work)";
}
}
}

View File

@@ -7,12 +7,12 @@ public class WorkResult<V> {
/**
* 执行的结果
*/
private V result;
private final V result;
/**
* 结果状态
*/
private ResultState resultState;
private Exception ex;
private final ResultState resultState;
private final Exception ex;
public WorkResult(V result, ResultState resultState) {
this(result, resultState, null);
@@ -24,10 +24,15 @@ public class WorkResult<V> {
this.ex = ex;
}
/**
* 返回不可修改的DEFAULT单例
*/
public static <V> WorkResult<V> defaultResult() {
return new WorkResult<>(null, ResultState.DEFAULT);
return (WorkResult<V>) DEFAULT;
}
private static final WorkResult<?> DEFAULT = new WorkResult<>(null, ResultState.DEFAULT);
@Override
public String toString() {
return "WorkResult{" +
@@ -41,23 +46,11 @@ public class WorkResult<V> {
return ex;
}
public void setEx(Exception ex) {
this.ex = ex;
}
public V getResult() {
return result;
}
public void setResult(V result) {
this.result = result;
}
public ResultState getResultState() {
return resultState;
}
public void setResultState(ResultState resultState) {
this.resultState = resultState;
}
}

View File

@@ -0,0 +1,100 @@
package com.jd.platform.async.wrapper;
import com.jd.platform.async.callback.ICallback;
import com.jd.platform.async.callback.IWorker;
import com.jd.platform.async.openutil.collection.DirectedGraph;
import com.jd.platform.async.openutil.collection.Graph;
import com.jd.platform.async.wrapper.strategy.WrapperStrategy;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
* 快速构造{@link WorkerWrapper},少废话!
* <p>
* 直接设置属性不用麻烦Builder设置来设置去
* 请 注 意:构造方法不会检查参数合法性,请程序员自己保证参数合法。
* <p>
* 将关系存储于有向图中{@link DirectedGraph}以节省每个wrapper都要保存节点数据的开销。
* </p>
*
* @author create by TcSnZh on 2021/5/13-上午11:54
*/
public class QuickBuildWorkerWrapper<T, V> extends WorkerWrapper<T, V> {
private final DirectedGraph<WorkerWrapper<?, ?>, Object> graph;
private volatile Set<WorkerWrapper<?, ?>> nextWrappersCache;
private volatile Set<WorkerWrapper<?, ?>> dependWrappersCache;
/**
* 构造函数,传入所有属性
*
* @param id {@link WorkerWrapper#id}
* @param param {@link WorkerWrapper#param}
* @param worker {@link WorkerWrapper#worker}
* @param callback {@link WorkerWrapper#callback}
* @param allowInterrupt {@link WorkerWrapper#allowInterrupt}
* @param enableTimeout {@link WorkerWrapper#enableTimeout}
* @param timeoutLength {@link WorkerWrapper#timeoutLength}
* @param timeoutUnit {@link WorkerWrapper#timeoutLength}
* @param wrapperStrategy {@link WorkerWrapper#timeoutUnit}
* @param wrapperGraph 将节点信息保存在图中,而不是如{@link StableWorkerWrapper}在每个wrapper中都保存节点信息。
* <p>
* {@link WorkerWrapper#getDependWrappers()}与{@link WorkerWrapper#getNextWrappers()}方法
* 将从本图中读取依赖顺序。除此之外,本类不会对本图进行任何修改操作。
* 因此,传入的此图应当保证读取时的线程安全。
* </p>
*/
public QuickBuildWorkerWrapper(String id,
T param,
IWorker<T, V> worker,
ICallback<T, V> callback,
boolean allowInterrupt,
boolean enableTimeout,
long timeoutLength,
TimeUnit timeoutUnit,
WrapperStrategy wrapperStrategy,
DirectedGraph<WorkerWrapper<?, ?>, Object> wrapperGraph) {
super(id, worker, callback, allowInterrupt, enableTimeout, timeoutLength, timeoutUnit, wrapperStrategy);
graph = wrapperGraph;
super.param = param;
State.setState(state, State.BUILDING, State.INIT);
}
@Override
public Set<WorkerWrapper<?, ?>> getNextWrappers() {
if (nextWrappersCache == null) {
synchronized (this) {
if (nextWrappersCache == null) {
nextWrappersCache = graph.getRelationFrom(this).stream()
.map(Graph.Entry::getTo).collect(Collectors.toSet());
}
}
}
return nextWrappersCache;
}
@Override
public Set<WorkerWrapper<?, ?>> getDependWrappers() {
if (dependWrappersCache == null) {
synchronized (this) {
if (dependWrappersCache == null) {
dependWrappersCache = graph.getRelationTo(this).stream()
.map(Graph.Entry::getFrom).collect(Collectors.toSet());
}
}
}
return dependWrappersCache;
}
@Override
void setNextWrappers(Set<WorkerWrapper<?, ?>> nextWrappers) {
throw new UnsupportedOperationException();
}
@Override
void setDependWrappers(Set<WorkerWrapper<?, ?>> dependWrappers) {
throw new UnsupportedOperationException();
}
}

View File

@@ -4,15 +4,22 @@ import com.jd.platform.async.callback.ICallback;
import com.jd.platform.async.callback.IWorker;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* {@link WorkerWrapper}默认实现类将上下游Wrapper保存在自己的Set中
*
* @author create by TcSnZh on 2021/5/6-下午2:41
*/
class StableWorkerWrapper<T, V> extends WorkerWrapper<T, V> {
StableWorkerWrapper(String id, IWorker<T, V> worker, T param, ICallback<T, V> callback) {
super(id, worker, param, callback);
public class StableWorkerWrapper<T, V> extends WorkerWrapper<T, V> {
public StableWorkerWrapper(String id,
IWorker<T, V> worker,
ICallback<T, V> callback,
boolean allowInterrupt,
boolean enableTimeout,
long timeoutLength,
TimeUnit timeoutUnit) {
super(id, worker, callback, allowInterrupt, enableTimeout, timeoutLength, timeoutUnit);
}
/**
@@ -45,7 +52,6 @@ class StableWorkerWrapper<T, V> extends WorkerWrapper<T, V> {
return nextWrappers;
}
// ========== package impl ==========
@Override
@@ -54,7 +60,7 @@ class StableWorkerWrapper<T, V> extends WorkerWrapper<T, V> {
}
@Override
Set<WorkerWrapper<?, ?>> getDependWrappers() {
public Set<WorkerWrapper<?, ?>> getDependWrappers() {
return dependWrappers;
}

View File

@@ -1,10 +1,14 @@
package com.jd.platform.async.wrapper;
import com.jd.platform.async.exception.SkippedException;
import com.jd.platform.async.callback.ICallback;
import com.jd.platform.async.callback.IWorker;
import com.jd.platform.async.worker.WorkResult;
import com.jd.platform.async.wrapper.skipstrategy.SkipStrategy;
import com.jd.platform.async.wrapper.actionstrategy.*;
import com.jd.platform.async.wrapper.strategy.depend.DependMustStrategyMapper;
import com.jd.platform.async.wrapper.strategy.depend.DependOnUpWrapperStrategy;
import com.jd.platform.async.wrapper.strategy.depend.DependOnUpWrapperStrategyMapper;
import com.jd.platform.async.wrapper.strategy.depend.DependenceStrategy;
import com.jd.platform.async.wrapper.strategy.skip.SkipStrategy;
import java.util.*;
import java.util.concurrent.TimeUnit;
@@ -59,15 +63,15 @@ class StableWorkerWrapperBuilder<T, V, BUILDER_SUB_CLASS extends StableWorkerWra
/**
* 存储自己需要特殊对待的dependWrapper集合
*/
private Map<WorkerWrapper<?, ?>, DependWrapperActionStrategy> dependWrapperActionStrategyMap;
private Map<WorkerWrapper<?, ?>, DependOnUpWrapperStrategy> dependWrapperActionStrategyMap;
/**
* 存储需要特殊对待自己的nextWrapper集合
*/
private Map<WorkerWrapper<?, ?>, DependWrapperActionStrategy> selfIsSpecialMap;
private Map<WorkerWrapper<?, ?>, DependOnUpWrapperStrategy> selfIsSpecialMap;
/**
* 一个保存以must=true方式传入的WorkerWrapper的集合
* <p/>
* 该Set将会加入到{@link WorkerWrapper.WrapperStrategy#getDependMustStrategyMapper().mustDependSet}之中
* 该Set将会加入到{@link WorkerWrapper.StableWrapperStrategy#getDependMustStrategyMapper().mustDependSet}之中
*/
private Set<WorkerWrapper<?, ?>> mustDependSet;
/**
@@ -93,6 +97,9 @@ class StableWorkerWrapperBuilder<T, V, BUILDER_SUB_CLASS extends StableWorkerWra
private boolean enableTimeOut = false;
private long time = -1;
private TimeUnit unit = null;
/**
* 是否允许被打断
*/
private boolean allowInterrupt = false;
/**
@@ -166,7 +173,7 @@ class StableWorkerWrapperBuilder<T, V, BUILDER_SUB_CLASS extends StableWorkerWra
}
@Override
public SetDependImpl specialDependWrapper(DependWrapperActionStrategy strategy, WorkerWrapper<?, ?> wrapper) {
public SetDependImpl specialDependWrapper(DependOnUpWrapperStrategy strategy, WorkerWrapper<?, ?> wrapper) {
if (strategy == null || wrapper == null) {
return this;
}
@@ -226,7 +233,7 @@ class StableWorkerWrapperBuilder<T, V, BUILDER_SUB_CLASS extends StableWorkerWra
}
@Override
public SetNextImpl specialToNextWrapper(DependWrapperActionStrategy strategy, WorkerWrapper<?, ?> wrapper) {
public SetNextImpl specialToNextWrapper(DependOnUpWrapperStrategy strategy, WorkerWrapper<?, ?> wrapper) {
if (strategy == null || wrapper == null) {
return this;
}
@@ -259,33 +266,48 @@ class StableWorkerWrapperBuilder<T, V, BUILDER_SUB_CLASS extends StableWorkerWra
@Override
public SetTimeOutImpl setTime(long time, TimeUnit unit) {
if (time <= 0 || unit == null) {
throw new IllegalStateException("Illegal argument : time=" + time + " must > 0, unit=" + unit + " must not null");
throw new IllegalStateException("Illegal argument : time=" + time + " must > 0, unit=" + unit + " require not null");
}
StableWorkerWrapperBuilder.this.time = time;
StableWorkerWrapperBuilder.this.unit = unit;
return this;
}
@Override
public SetTimeOutImpl allowInterrupt(boolean allow) {
StableWorkerWrapperBuilder.this.allowInterrupt = allow;
return this;
}
@Override
public BUILDER_SUB_CLASS end() {
return returnThisBuilder();
}
}
@Override
public WorkerWrapperBuilder<T, V> allowInterrupt(boolean allow) {
allowInterrupt = allow;
return returnThisBuilder();
}
@Override
public WorkerWrapper<T, V> build() {
isBuilding = true;
// ========== 设置单wrapper超时检查 ==========
{
if (enableTimeOut) {
if (time <= 0) {
throw new IllegalArgumentException("timeout time " + time + " must > 0");
}
if (unit == null) {
throw new IllegalArgumentException(new NullPointerException("timeout unit require not null"));
}
}
}
// ========== 构造wrapper ==========
WorkerWrapper<T, V> wrapper = new StableWorkerWrapper<>(
id == null ? UUID.randomUUID().toString() : id,
worker,
param,
callback
callback,
allowInterrupt,
enableTimeOut,
time,
unit
);
wrapper.setDependWrappers(new LinkedHashSet<>());
wrapper.setNextWrappers(new LinkedHashSet<>());
@@ -309,6 +331,7 @@ class StableWorkerWrapperBuilder<T, V, BUILDER_SUB_CLASS extends StableWorkerWra
wrapper.getWrapperStrategy().setDependMustStrategyMapper(new DependMustStrategyMapper()
.addDependMust(mustDependSet));
}
//noinspection deprecation
wrapper.getWrapperStrategy().setDependenceStrategy(DependenceStrategy.IF_MUST_SET_NOT_EMPTY_ALL_SUCCESS_ELSE_ANY);
} else {
if (mustDependSet != null && mustDependSet.size() > 0) {
@@ -320,7 +343,7 @@ class StableWorkerWrapperBuilder<T, V, BUILDER_SUB_CLASS extends StableWorkerWra
wrapper.getWrapperStrategy().setDependenceStrategy(dependenceStrategy);
}
if (dependWrapperActionStrategyMap != null && dependWrapperActionStrategyMap.size() > 0) {
DependWrapperStrategyMapper mapper = new DependWrapperStrategyMapper();
DependOnUpWrapperStrategyMapper mapper = new DependOnUpWrapperStrategyMapper();
dependWrapperActionStrategyMap.forEach(mapper::putMapping);
wrapper.getWrapperStrategy().setDependWrapperStrategyMapper(mapper);
}
@@ -329,8 +352,14 @@ class StableWorkerWrapperBuilder<T, V, BUILDER_SUB_CLASS extends StableWorkerWra
.ifPresent(mustMapper -> mustMapper.addDependMust(wrapper)));
}
if (selfIsSpecialMap != null && selfIsSpecialMap.size() > 0) {
selfIsSpecialMap.forEach((next, strategy) -> Optional.ofNullable(next.getWrapperStrategy().getDependWrapperStrategyMapper())
.ifPresent(wrapperMapper -> wrapperMapper.putMapping(wrapper, strategy)));
selfIsSpecialMap.forEach((next, strategy) -> {
DependOnUpWrapperStrategyMapper dependOnUpWrapperStrategyMapper = next.getWrapperStrategy().getDependWrapperStrategyMapper();
if (dependOnUpWrapperStrategyMapper == null) {
next.getWrapperStrategy().setDependWrapperStrategyMapper(
dependOnUpWrapperStrategyMapper = new DependOnUpWrapperStrategyMapper());
}
dependOnUpWrapperStrategyMapper.putMapping(wrapper, strategy);
});
}
}
// ========== 设置检查是否跳过策略 ==========
@@ -344,18 +373,9 @@ class StableWorkerWrapperBuilder<T, V, BUILDER_SUB_CLASS extends StableWorkerWra
wrapper.getWrapperStrategy().setSkipStrategy(skipStrategy);
}
}
// ========== 设置单wrapper超时检查 ==========
{
if (enableTimeOut) {
if (time <= 0) {
throw new IllegalStateException("timeout time " + time + " must > " + 0);
}
if (unit == null) {
throw new IllegalStateException("timeout unit must not null");
}
wrapper.setTimeOut(new WorkerWrapper.TimeOutProperties(true, time, unit, allowInterrupt, wrapper));
}
}
// ========== end ==========
wrapper.state.set(WorkerWrapper.State.INIT.id);
wrapper.setParam(param);
return wrapper;
}
@@ -363,8 +383,8 @@ class StableWorkerWrapperBuilder<T, V, BUILDER_SUB_CLASS extends StableWorkerWra
/**
* @deprecated 建议使用 {@link WorkerWrapperBuilder#depends(WorkerWrapper[])}
* {@link WorkerWrapperBuilder#setDepend()}设置更多选项例如{@link WorkerWrapperBuilder.SetDepend#wrapper(WorkerWrapper[])}
* 如果是想要必须依赖的功能则使用{@link WorkerWrapperBuilder.SetDepend#mustRequireWrapper(WorkerWrapper[])}
* {@link WorkerWrapperBuilder#setDepend()}设置更多选项例如{@link SetDepend#wrapper(WorkerWrapper[])}
* 如果是想要必须依赖的功能则使用{@link SetDepend#mustRequireWrapper(WorkerWrapper[])}
*/
@Deprecated
public BUILDER_SUB_CLASS depend(WorkerWrapper<?, ?>... wrappers) {
@@ -379,8 +399,8 @@ class StableWorkerWrapperBuilder<T, V, BUILDER_SUB_CLASS extends StableWorkerWra
/**
* @deprecated 建议使用 {@link WorkerWrapperBuilder#depends(WorkerWrapper[])}
* {@link WorkerWrapperBuilder#setDepend()}设置更多选项例如{@link WorkerWrapperBuilder.SetDepend#wrapper(WorkerWrapper)}
* 如果是想要必须依赖的功能则使用{@link WorkerWrapperBuilder.SetDepend#mustRequireWrapper(WorkerWrapper[])}
* {@link WorkerWrapperBuilder#setDepend()}设置更多选项例如{@link SetDepend#wrapper(WorkerWrapper)}
* 如果是想要必须依赖的功能则使用{@link SetDepend#mustRequireWrapper(WorkerWrapper[])}
*/
@Deprecated
public BUILDER_SUB_CLASS depend(WorkerWrapper<?, ?> wrapper) {
@@ -388,7 +408,7 @@ class StableWorkerWrapperBuilder<T, V, BUILDER_SUB_CLASS extends StableWorkerWra
}
/**
* @deprecated 建议使用 {@link WorkerWrapperBuilder.SetDepend#requireWrapper(WorkerWrapper, boolean)}}
* @deprecated 建议使用 {@link SetDepend#requireWrapper(WorkerWrapper, boolean)}}
*/
@Deprecated
public BUILDER_SUB_CLASS depend(WorkerWrapper<?, ?> wrapper, boolean isMust) {
@@ -459,7 +479,7 @@ class StableWorkerWrapperBuilder<T, V, BUILDER_SUB_CLASS extends StableWorkerWra
* 默认为true
*
* @param needCheckNextWrapperResult 设为true后如果之后的Wrapper已经执行完毕
* 则跳过本Wrapper并设置{@link WorkResult#getEx()}{@link com.jd.platform.async.exception.SkippedException}
* 则跳过本Wrapper并设置{@link WorkResult#getEx()}{@link SkippedException}
* @deprecated v1.5中已经废弃请使用
*/
@Deprecated
@@ -471,6 +491,7 @@ class StableWorkerWrapperBuilder<T, V, BUILDER_SUB_CLASS extends StableWorkerWra
// util method
private BUILDER_SUB_CLASS returnThisBuilder() {
//noinspection unchecked
return (BUILDER_SUB_CLASS) this;
}

View File

@@ -0,0 +1,786 @@
package com.jd.platform.async.wrapper;
import com.jd.platform.async.exception.CancelSkippedException;
import com.jd.platform.async.worker.ResultState;
import com.jd.platform.async.worker.WorkResult;
import com.jd.platform.async.callback.DefaultCallback;
import com.jd.platform.async.callback.ICallback;
import com.jd.platform.async.callback.IWorker;
import com.jd.platform.async.exception.SkippedException;
import com.jd.platform.async.executor.PollingCenter;
import com.jd.platform.async.executor.timer.SystemClock;
import com.jd.platform.async.wrapper.strategy.WrapperStrategy;
import com.jd.platform.async.wrapper.strategy.depend.DependMustStrategyMapper;
import com.jd.platform.async.wrapper.strategy.depend.DependOnUpWrapperStrategyMapper;
import com.jd.platform.async.wrapper.strategy.depend.DependenceAction;
import com.jd.platform.async.wrapper.strategy.depend.DependenceStrategy;
import com.jd.platform.async.wrapper.strategy.skip.SkipStrategy;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import static com.jd.platform.async.wrapper.WorkerWrapper.State.AFTER_WORK;
import static com.jd.platform.async.wrapper.WorkerWrapper.State.BUILDING;
import static com.jd.platform.async.wrapper.WorkerWrapper.State.ERROR;
import static com.jd.platform.async.wrapper.WorkerWrapper.State.INIT;
import static com.jd.platform.async.wrapper.WorkerWrapper.State.SKIP;
import static com.jd.platform.async.wrapper.WorkerWrapper.State.STARTED;
import static com.jd.platform.async.wrapper.WorkerWrapper.State.SUCCESS;
import static com.jd.platform.async.wrapper.WorkerWrapper.State.WORKING;
import static com.jd.platform.async.wrapper.WorkerWrapper.State.states_all;
import static com.jd.platform.async.wrapper.WorkerWrapper.State.states_of_beforeWorkingEnd;
import static com.jd.platform.async.wrapper.WorkerWrapper.State.states_of_notWorked;
import static com.jd.platform.async.wrapper.WorkerWrapper.State.states_of_skipOrAfterWork;
import static com.jd.platform.async.wrapper.WorkerWrapper.State.*;
/**
* 对每个worker及callback进行包装一对一
* <p/>
* v1.5时将其抽取为抽象类,以解耦并提高扩展性。
*
* @author wuweifeng wrote on 2019-11-19.
*/
@SuppressWarnings("AlibabaAbstractClassShouldStartWithAbstractNaming")
public abstract class WorkerWrapper<T, V> {
// ========== 固定属性 ==========
/**
* 该wrapper的唯一标识
*/
protected final String id;
protected final IWorker<T, V> worker;
protected final ICallback<T, V> callback;
/**
* 各种策略的封装类。
*/
private final WrapperStrategy wrapperStrategy;
/**
* 是否允许被打断
*/
protected final boolean allowInterrupt;
/**
* 是否启动超时检查
*/
final boolean enableTimeout;
/**
* 超时时间长度
*/
final long timeoutLength;
/**
* 超时时间单位
*/
final TimeUnit timeoutUnit;
// ========== 临时属性 ==========
/**
* worker将来要处理的param
*/
protected volatile T param;
/**
* 原子设置wrapper的状态
* <p>
* {@link State}此枚举类枚举了state值所代表的状态枚举。
*/
protected final AtomicInteger state = new AtomicInteger(BUILDING.id);
/**
* 该值将在{@link IWorker#action(Object, Map)}进行时设为当前线程在任务开始前或结束后都为null。
*/
protected final AtomicReference<Thread> doWorkingThread = new AtomicReference<>();
/**
* 也是个钩子变量,用来存临时的结果
*/
protected final AtomicReference<WorkResult<V>> workResult = new AtomicReference<>(null);
WorkerWrapper(String id,
IWorker<T, V> worker,
ICallback<T, V> callback,
boolean allowInterrupt,
boolean enableTimeout,
long timeoutLength,
TimeUnit timeoutUnit,
WrapperStrategy wrapperStrategy
) {
if (worker == null) {
throw new NullPointerException("async.worker is null");
}
this.worker = worker;
this.id = id;
//允许不设置回调
if (callback == null) {
callback = new DefaultCallback<>();
}
this.callback = callback;
this.allowInterrupt = allowInterrupt;
this.enableTimeout = enableTimeout;
this.timeoutLength = timeoutLength;
this.timeoutUnit = timeoutUnit;
this.wrapperStrategy = wrapperStrategy;
}
WorkerWrapper(String id,
IWorker<T, V> worker,
ICallback<T, V> callback,
boolean allowInterrupt,
boolean enableTimeout,
long timeoutLength,
TimeUnit timeoutUnit) {
this(id, worker, callback, allowInterrupt, enableTimeout, timeoutLength, timeoutUnit, new StableWrapperStrategy());
}
// ========== public ==========
/**
* 外部调用本线程运行此wrapper的入口方法。
* 该方法将会确定这组wrapper所属的group。
*
* @param executorService 该ExecutorService将成功运行后在nextWrapper有多个时被使用于多线程调用。
* @param remainTime 剩下的时间
* @param group wrapper组
* @throws IllegalStateException 当wrapper正在building状态时被启动则会抛出该异常。
*/
public void work(ExecutorService executorService,
long remainTime,
WorkerWrapperGroup group) {
work(executorService, null, remainTime, group);
}
public String getId() {
return id;
}
/**
* 返回{@link #workResult}的值。
* 若调用此方法时workResult还未设置将会返回{@link WorkResult#defaultResult()}。
*/
public WorkResult<V> getWorkResult() {
WorkResult<V> res = workResult.get();
return res == null ? WorkResult.defaultResult() : res;
}
public void setParam(T param) {
this.param = param;
}
public State getState() {
return of(state.get());
}
/**
* 获取下游Wrapper
*/
public abstract Set<WorkerWrapper<?, ?>> getNextWrappers();
/**
* 获取上游wrapper
*/
public abstract Set<WorkerWrapper<?, ?>> getDependWrappers();
/**
* 获取本wrapper的超时情况。如有必要还会修改wrapper状态。
*
* @param withEndIt 如果为true在检查出已经超时的时候会将其快速结束。
* @param startTime 起始时间
* @param totalTimeLength 总任务时长
* @return 超时返回-1L结束但未超时返回0L尚未结束且未超时返回与deadline的差值
* <p>
* 当没有超时若该wrapper已经结束但没有超时返回 0L 。
* <p>
* 如果该wrapper单独了设置超时策略并正在运行返回距离超时策略限时相差的毫秒值。
* 例如设置10ms超时此时已经开始3ms则返回 7L。
* 如果此差值<1则返回 1L。
* <p>
* 如果已经超时,则返回 -1L。
* </p>
*/
public long checkTimeout(boolean withEndIt, long startTime, long totalTimeLength) {
do {
WorkResult<V> _workResult = workResult.get();
// 如果已经有结果了,就根据结果值判断
if (_workResult != null) {
return _workResult.getResultState() == ResultState.TIMEOUT ? -1L : 0L;
}
// 如果还没有出结果
// 判断是否超时
long now = SystemClock.now();
if (totalTimeLength < now - startTime
|| enableTimeout && timeoutUnit.toMillis(timeoutLength) < now - startTime) {
// 如果需要处理该wrapper的状态
if (withEndIt) {
// CAS一个超时的结果
if (!workResult.compareAndSet(
null,
new WorkResult<>(null, ResultState.TIMEOUT, null))
) {
// 就在想CAS的时候出结果了就采用新的结果重新判断一次
continue;
}
fastFail(true, null, false);
}
return -1L;
}
// 正在运行,尚未超时
else {
return Math.max(1, startTime + totalTimeLength - now);
}
} while (true);
}
/**
* 直接取消wrapper运行。
* 如果状态在 {@link State#states_of_beforeWorkingEnd}中,则调用 {@link #fastFail(boolean, Exception, boolean)}。
*/
public void cancel() {
if (State.setState(state, states_of_beforeWorkingEnd, SKIP, null)) {
fastFail(false, new CancelSkippedException(), true);
}
}
public WrapperStrategy getWrapperStrategy() {
return wrapperStrategy;
}
// ========== protected ==========
/**
* 工作的核心方法。
*
* @param fromWrapper 代表这次work是由哪个上游wrapper发起的。如果是首个Wrapper则为null。
* @param remainTime 剩余时间。
* @throws IllegalStateException 当wrapper正在building状态时被启动则会抛出该异常。
*/
protected void work(ExecutorService executorService,
WorkerWrapper<?, ?> fromWrapper,
long remainTime,
WorkerWrapperGroup group
) {
long now = SystemClock.now();
// ================================================
// 以下是一些lambda。
// 因为抽取成方法反而不好传参、污染类方法,所以就这么干了
final Consumer<Boolean> __function__callbackResult =
success -> {
WorkResult<V> _workResult = getWorkResult();
try {
callback.result(success, param, _workResult);
} catch (Exception e) {
if (setState(state, states_of_skipOrAfterWork, ERROR, null)) {
fastFail(false, e, _workResult.getEx() instanceof SkippedException);
}
}
};
final Runnable __function__callbackResultOfFalse_beginNext =
() -> {
__function__callbackResult.accept(false);
beginNext(executorService, now, remainTime, group);
};
final BiConsumer<Boolean, Exception> __function__fastFail_callbackResult$false_beginNext =
(fastFail_isTimeout, fastFail_exception) -> {
boolean isSkip = fastFail_exception instanceof SkippedException;
fastFail(fastFail_isTimeout && !isSkip, fastFail_exception, isSkip);
__function__callbackResultOfFalse_beginNext.run();
};
final Runnable __function__doWork =
() -> {
if (setState(state, STARTED, WORKING)) {
try {
fire(group);
} catch (Exception e) {
if (setState(state, WORKING, ERROR)) {
__function__fastFail_callbackResult$false_beginNext.accept(false, e);
}
return;
}
}
if (setState(state, WORKING, AFTER_WORK)) {
__function__callbackResult.accept(true);
beginNext(executorService, now, remainTime, group);
}
};
// ================================================
// 开始执行
try {
if (isState(state, BUILDING)) {
throw new IllegalStateException("wrapper can't work because state is BUILDING ! wrapper is " + this);
}
// 判断是否整组取消
if (group.isWaitingCancel() || group.isCancelled()) {
cancel();
return;
}
// 总的已经超时了,就快速失败,进行下一个
if (remainTime <= 0) {
if (setState(state, states_of_beforeWorkingEnd, ERROR, null)) {
__function__fastFail_callbackResult$false_beginNext.accept(true, null);
}
return;
}
// 如果自己已经执行过了。
// 可能有多个依赖,其中的一个依赖已经执行完了,并且自己也已开始执行或执行完毕。当另一个依赖执行完毕,又进来该方法时,就不重复处理了
final AtomicReference<State> oldStateRef = new AtomicReference<>(null);
if (!setState(state, states_of_notWorked, STARTED, oldStateRef::set)) {
return;
}
// 如果wrapper是第一次要调用callback.begin
if (oldStateRef.get() == INIT) {
try {
callback.begin();
} catch (Exception e) {
// callback.begin 发生异常
if (setState(state, states_of_beforeWorkingEnd, ERROR, null)) {
__function__fastFail_callbackResult$false_beginNext.accept(false, e);
}
return;
}
}
//如果fromWrapper为null说明自己就是第一批要执行的
if (fromWrapper == null) {
// 首当其冲,开始工作
__function__doWork.run();
return;
}
// 每个线程都需要判断是否要跳过自己,该方法可能会跳过正在工作的自己。
final WrapperStrategy wrapperStrategy = getWrapperStrategy();
if (wrapperStrategy.shouldSkip(getNextWrappers(), this, fromWrapper)) {
if (setState(state, STARTED, SKIP)) {
__function__fastFail_callbackResult$false_beginNext.accept(false, new SkippedException());
}
return;
}
// 如果是由其他wrapper调用而运行至此则使用策略器决定自己的行为
DependenceAction.WithProperty judge =
wrapperStrategy.judgeAction(getDependWrappers(), this, fromWrapper);
switch (judge.getDependenceAction()) {
case TAKE_REST:
return;
case FAST_FAIL:
if (setState(state, STARTED, ERROR)) {
// 根据FAST_FAIL.fastFailException()设置的属性值来设置fastFail方法的参数
ResultState resultState = judge.getResultState();
__function__fastFail_callbackResult$false_beginNext.accept(
resultState == ResultState.TIMEOUT,
judge.getFastFailException()
);
}
return;
case START_WORK:
__function__doWork.run();
return;
case JUDGE_BY_AFTER:
default:
throw new IllegalStateException(
"策略配置错误不应当在WorkerWrapper中返回JUDGE_BY_AFTER或其他无效值 : this=" + this +
",fromWrapper=" + fromWrapper);
}
} catch (Exception e) {
// wrapper本身抛出了不该有的异常
setState(state, states_all, ERROR, null);
NotExpectedException ex = new NotExpectedException(e, this);
workResult.set(new WorkResult<>(null, ResultState.EXCEPTION, ex));
__function__fastFail_callbackResult$false_beginNext.accept(false, ex);
}
}
/**
* 本工作线程执行自己的job.
* <p/>
* 本方法不负责校验状态。请在调用前自行检验
*/
protected void fire(WorkerWrapperGroup group) {
try {
doWorkingThread.set(Thread.currentThread());
//执行耗时操作
V result = worker.action(param, group.getForParamUseWrappers());
workResult.compareAndSet(
null,
new WorkResult<>(result, ResultState.SUCCESS)
);
} finally {
doWorkingThread.set(null);
}
}
/**
* 快速失败。
* 该方法不负责检查状态,请自行控制。
*
* @param isTimeout 是否是因为超时而快速失败
* @param e 设置异常信息到{@link WorkResult#getEx()}
*/
protected void fastFail(boolean isTimeout, Exception e, boolean isSkip) {
// 试图打断正在执行{@link IWorker#action(Object, Map)}的线程
Thread _doWorkingThread;
if ((_doWorkingThread = doWorkingThread.get()) != null
// 不会打断自己
&& !Objects.equals(Thread.currentThread(), _doWorkingThread)) {
_doWorkingThread.interrupt();
}
// 尚未处理过结果则设置
workResult.compareAndSet(null, new WorkResult<>(
worker.defaultValue(),
isTimeout ? ResultState.TIMEOUT : (isSkip ? ResultState.DEFAULT : ResultState.EXCEPTION),
e
));
}
/**
* 进行下一个任务
* <p/>
* 本方法不负责校验状态。请在调用前自行检验
*/
protected void beginNext(ExecutorService executorService, long now, long remainTime, WorkerWrapperGroup group) {
//花费的时间
final long costTime = SystemClock.now() - now;
final long nextRemainTIme = remainTime - costTime;
Set<WorkerWrapper<?, ?>> nextWrappers = getNextWrappers();
if (nextWrappers == null) {
PollingCenter.getInstance().checkGroup(group.new CheckFinishTask());
return;
}
// nextWrappers只有一个就用本线程继续跑。
if (nextWrappers.size() == 1) {
WorkerWrapper<?, ?> next = null;
try {
next = nextWrappers.stream().findFirst().get();
group.addWrapper(next);
setState(state, AFTER_WORK, SUCCESS);
} finally {
PollingCenter.getInstance().checkGroup(group.new CheckFinishTask());
if (next != null) {
next.work(executorService, this, nextRemainTIme, group);
}
}
}
// nextWrappers有多个
else {
try {
group.addWrapper(nextWrappers);
nextWrappers.forEach(next -> executorService.submit(() ->
next.work(executorService, this, nextRemainTIme, group))
);
setState(state, AFTER_WORK, SUCCESS);
} finally {
PollingCenter.getInstance().checkGroup(group.new CheckFinishTask());
}
}
}
// ========== hashcode and equals ==========
@Override
public boolean equals(Object o) {
return super.equals(o);
}
/**
* {@code return id.hashCode();}返回id值的hashcode
*/
@Override
public int hashCode() {
// final String id can use to .hashcode() .
return id.hashCode();
}
// ========== builder ==========
public static <T, V> WorkerWrapperBuilder<T, V> builder() {
return new Builder<>();
}
/**
* 自v1.5,该类被抽取到{@link StableWorkerWrapperBuilder}抽象类,兼容之前的版本。
*/
public static class Builder<W, C> extends StableWorkerWrapperBuilder<W, C, Builder<W, C>> {
/**
* @deprecated 建议使用 {@link #builder()}返回{@link WorkerWrapperBuilder}接口以调用v1.5之后的规范api
*/
@SuppressWarnings("DeprecatedIsStillUsed")
@Deprecated
public Builder() {
}
}
// ========== package access methods ==========
abstract void setNextWrappers(Set<WorkerWrapper<?, ?>> nextWrappers);
abstract void setDependWrappers(Set<WorkerWrapper<?, ?>> dependWrappers);
// ========== toString ==========
@Override
public String toString() {
final StringBuilder sb = new StringBuilder(400)
.append("WorkerWrapper{id=").append(id)
.append(", state=").append(of(state.get()))
.append(", param=").append(param)
.append(", workResult=").append(workResult)
.append(", allowInterrupt=").append(allowInterrupt)
.append(", enableTimeout=").append(enableTimeout)
.append(", timeoutLength=").append(timeoutLength)
.append(", timeoutUnit=").append(timeoutUnit)
// 防止循环引用这里只输出相关Wrapper的id
.append(", dependWrappers::getId=[");
final Set<WorkerWrapper<?, ?>> dependWrappers = getDependWrappers();
dependWrappers.stream().map(WorkerWrapper::getId).forEach(wrapperId -> sb.append(wrapperId).append(", "));
if (dependWrappers.size() > 0) {
sb.delete(sb.length() - 2, sb.length());
}
sb
.append("], nextWrappers::getId=[");
final Set<WorkerWrapper<?, ?>> nextWrappers = getNextWrappers();
nextWrappers.stream().map(WorkerWrapper::getId).forEach(wrapperId -> sb.append(wrapperId).append(", "));
if (nextWrappers.size() > 0) {
sb.delete(sb.length() - 2, sb.length());
}
sb
.append("], doWorkingThread=").append(doWorkingThread.get())
.append(", worker=").append(worker)
.append(", callback=").append(callback)
.append(", wrapperStrategy=").append(wrapperStrategy)
.append('}');
return sb.toString();
}
/**
* 一个通用的策略器实现类,提供了修改的功能。并兼容之前的代码。
*/
public static class StableWrapperStrategy extends WrapperStrategy.AbstractWrapperStrategy {
private DependOnUpWrapperStrategyMapper dependOnUpWrapperStrategyMapper;
private DependMustStrategyMapper dependMustStrategyMapper;
private DependenceStrategy dependenceStrategy;
private SkipStrategy skipStrategy;
@Override
public DependOnUpWrapperStrategyMapper getDependWrapperStrategyMapper() {
return dependOnUpWrapperStrategyMapper;
}
@Override
public void setDependWrapperStrategyMapper(DependOnUpWrapperStrategyMapper dependOnUpWrapperStrategyMapper) {
this.dependOnUpWrapperStrategyMapper = dependOnUpWrapperStrategyMapper;
}
@Override
public DependMustStrategyMapper getDependMustStrategyMapper() {
return dependMustStrategyMapper;
}
@Override
public void setDependMustStrategyMapper(DependMustStrategyMapper dependMustStrategyMapper) {
this.dependMustStrategyMapper = dependMustStrategyMapper;
}
@Override
public DependenceStrategy getDependenceStrategy() {
return dependenceStrategy;
}
@Override
public void setDependenceStrategy(DependenceStrategy dependenceStrategy) {
this.dependenceStrategy = dependenceStrategy;
}
@Override
public SkipStrategy getSkipStrategy() {
return skipStrategy;
}
@Override
public void setSkipStrategy(SkipStrategy skipStrategy) {
this.skipStrategy = skipStrategy;
}
}
/**
* state状态枚举工具类
*/
public enum State {
/**
* 初始化中builder正在设置其数值
*/
BUILDING(-1),
/**
* 初始化完成,但是还未执行过。
*/
INIT(0),
/**
* 执行过。
* 即至少进行了一次各种判定,例如判断 是否跳过/是否启动工作
*/
STARTED(1),
/**
* 工作状态
*/
WORKING(2),
/**
* 工作完成后的收尾工作例如调用下游wrapper
*/
AFTER_WORK(3),
/**
* wrapper成功执行结束
*/
SUCCESS(4),
/**
* wrapper失败了
*/
ERROR(5),
/**
* wrapper被跳过
*/
SKIP(6);
// public
public boolean finished() {
return this == SUCCESS || this == ERROR || this == SKIP;
}
// package
State(int id) {
this.id = id;
}
final int id;
// package-static
static final State[] states_of_notWorked = new State[]{INIT, STARTED};
static final State[] states_of_skipOrAfterWork = new State[]{SKIP, AFTER_WORK};
static final State[] states_of_beforeWorkingEnd = new State[]{INIT, STARTED, WORKING};
static final State[] states_all = new State[]{BUILDING, INIT, STARTED, WORKING, AFTER_WORK, SUCCESS, ERROR, SKIP};
/**
* 自旋+CAS的设置状态如果状态不在exceptValues返回内 或 没有设置成功则返回false。
*
* @param state {@link WorkerWrapper#state} 要被修改的AtomicInteger引用
* @param exceptValues 期望的值数组任何满足该值的state都会被修改
* @param newValue 新值
* @param withOperate 如果该参数不为null并且成功设置该函数将会被执行其参数为wrapper原子设置之前的旧状态。
* 之所以需要这个参数是因为当except值有多个时无法确定是哪个值被原子修改了。
* @return 返回是否成功设置。
*/
static boolean setState(AtomicInteger state,
State[] exceptValues,
State newValue,
Consumer<State> withOperate) {
int current;
boolean inExcepts;
while (true) {
// 判断当前值是否在exceptValues范围内
current = state.get();
inExcepts = false;
for (State exceptValue : exceptValues) {
if (inExcepts = current == exceptValue.id) {
break;
}
}
// 如果不在 exceptValues 范围内直接返回false。
if (!inExcepts) {
return false;
}
// 如果在 exceptValues 范围cas成功返回true失败即当前值被修改则自旋。
if (state.compareAndSet(current, newValue.id)) {
if (withOperate != null) {
withOperate.accept(of(current));
}
return true;
}
}
}
/**
* 自旋+CAS的设置状态如果状态不在exceptValues返回内 或 没有设置成功自旋后不在范围内则返回false。
*
* @param state {@link WorkerWrapper#state} 要被修改的AtomicInteger引用
* @param exceptValue 期望的值
* @param newValue 新值
* @return 返回是否成功设置。
*/
static boolean setState(AtomicInteger state,
State exceptValue,
State newValue) {
int current;
// 如果当前值与期望值相同
while ((current = state.get()) == exceptValue.id) {
// 则尝试CAS设置新值
if (state.compareAndSet(current, newValue.id)) {
return true;
}
// 如果当前值被改变,则尝试自旋
}
// 如果当前值与期望值不相同了就直接返回false
return false;
}
/**
* 自旋+CAS的判断是否在这些excepts范围内
*
* @param excepts 范围。
*/
@SuppressWarnings("unused")
static boolean inStates(AtomicInteger state, State... excepts) {
int current;
boolean inExcepts;
while (true) {
current = state.get();
inExcepts = false;
for (State except : excepts) {
if (current == except.id) {
inExcepts = true;
break;
}
}
if (state.get() == current) {
return inExcepts;
}
}
}
/**
* CAS的判断是否是某个状态
*/
static boolean isState(AtomicInteger state, @SuppressWarnings("SameParameterValue") State except) {
return state.compareAndSet(except.id, except.id);
}
static State of(int id) {
return id2state.get(id);
}
static final Map<Integer, State> id2state;
static {
HashMap<Integer, State> map = new HashMap<>();
for (State s : State.values()) {
map.put(s.id, s);
}
id2state = Collections.unmodifiableMap(map);
}
}
/**
* 这是因未知错误而引发的异常
*/
public static class NotExpectedException extends Exception {
public NotExpectedException(Throwable cause, WorkerWrapper<?, ?> wrapper) {
super("It's should not happened Exception . wrapper is " + wrapper, cause);
}
}
}

View File

@@ -2,10 +2,9 @@ package com.jd.platform.async.wrapper;
import com.jd.platform.async.callback.ICallback;
import com.jd.platform.async.callback.IWorker;
import com.jd.platform.async.worker.WorkResult;
import com.jd.platform.async.wrapper.actionstrategy.DependWrapperActionStrategy;
import com.jd.platform.async.wrapper.actionstrategy.DependenceStrategy;
import com.jd.platform.async.wrapper.skipstrategy.SkipStrategy;
import com.jd.platform.async.wrapper.strategy.depend.DependOnUpWrapperStrategy;
import com.jd.platform.async.wrapper.strategy.depend.DependenceStrategy;
import com.jd.platform.async.wrapper.strategy.skip.SkipStrategy;
import java.util.Collection;
import java.util.concurrent.TimeUnit;
@@ -113,9 +112,11 @@ public interface WorkerWrapperBuilder<T, V> {
* @param wrapper 需要设置特殊策略的Wrapper
* @param strategy 特殊策略
*/
SetDepend<T, V> specialDependWrapper(DependWrapperActionStrategy strategy, WorkerWrapper<?, ?> wrapper);
@SuppressWarnings("UnusedReturnValue")
SetDepend<T, V> specialDependWrapper(DependOnUpWrapperStrategy strategy, WorkerWrapper<?, ?> wrapper);
default SetDepend<T, V> specialDependWrapper(DependWrapperActionStrategy strategy, WorkerWrapper... wrappers) {
@SuppressWarnings("unused")
default SetDepend<T, V> specialDependWrapper(DependOnUpWrapperStrategy strategy, WorkerWrapper... wrappers) {
if (strategy == null || wrappers == null) {
return this;
}
@@ -157,6 +158,7 @@ public interface WorkerWrapperBuilder<T, V> {
return setDepend().wrapper(wrappers).end();
}
@SuppressWarnings("unused")
default WorkerWrapperBuilder<T, V> depends(Collection<WorkerWrapper> wrappers) {
return setDepend().wrapper(wrappers).end();
}
@@ -165,6 +167,7 @@ public interface WorkerWrapperBuilder<T, V> {
return setDepend().wrapper(wrappers).strategy(strategy).end();
}
@SuppressWarnings("unused")
default WorkerWrapperBuilder<T, V> depends(DependenceStrategy strategy, Collection<WorkerWrapper> wrappers) {
return setDepend().wrapper(wrappers).strategy(strategy).end();
}
@@ -205,6 +208,7 @@ public interface WorkerWrapperBuilder<T, V> {
*/
SetNext<T, V> mustToNextWrapper(WorkerWrapper<?, ?> wrapper);
@SuppressWarnings("unused")
default SetNext<T, V> requireToNextWrapper(WorkerWrapper<?, ?> wrapper, boolean must) {
return must ? mustToNextWrapper(wrapper) : wrapper(wrapper);
}
@@ -216,7 +220,7 @@ public interface WorkerWrapperBuilder<T, V> {
* @param wrapper 依赖本Wrapper的下游Wrapper
* @return 返回Builder自身
*/
SetNext<T, V> specialToNextWrapper(DependWrapperActionStrategy strategy, WorkerWrapper<?, ?> wrapper);
SetNext<T, V> specialToNextWrapper(DependOnUpWrapperStrategy strategy, WorkerWrapper<?, ?> wrapper);
WorkerWrapperBuilder<T, V> end();
}
@@ -230,6 +234,7 @@ public interface WorkerWrapperBuilder<T, V> {
return setNext().wrapper(wrappers).end();
}
@SuppressWarnings("unused")
default WorkerWrapperBuilder<T, V> nextOf(Collection<WorkerWrapper> wrappers) {
return setNext().wrapper(wrappers).end();
}
@@ -257,13 +262,6 @@ public interface WorkerWrapperBuilder<T, V> {
*/
SetTimeOut<T, V> setTime(long time, TimeUnit unit);
/**
* 是否允许被试图中断线程
*
* @param allow 是则true
*/
SetTimeOut<T, V> allowInterrupt(boolean allow);
WorkerWrapperBuilder<T, V> end();
}
@@ -274,13 +272,20 @@ public interface WorkerWrapperBuilder<T, V> {
* @param unit 时间单位
*/
default WorkerWrapperBuilder<T, V> timeout(long time, TimeUnit unit) {
return timeout(true, time, unit, false);
return timeout(true, time, unit);
}
default WorkerWrapperBuilder<T, V> timeout(boolean enableTimeOut, long time, TimeUnit unit, boolean allowInterrupt) {
return setTimeOut().enableTimeOut(enableTimeOut).setTime(time, unit).allowInterrupt(allowInterrupt).end();
default WorkerWrapperBuilder<T, V> timeout(boolean enableTimeOut, long time, TimeUnit unit) {
return setTimeOut().enableTimeOut(enableTimeOut).setTime(time, unit).end();
}
/**
* 是否允许被试图中断线程
*
* @param allow 是则true
*/
WorkerWrapperBuilder<T, V> allowInterrupt(boolean allow);
/**
* 构建Wrapper
*

View File

@@ -0,0 +1,212 @@
package com.jd.platform.async.wrapper;
import com.jd.platform.async.exception.CancelSkippedException;
import com.jd.platform.async.executor.PollingCenter;
import java.util.Collection;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Stream;
import com.jd.platform.async.executor.timer.SystemClock;
import com.jd.platform.async.openutil.timer.*;
/**
* @author create by TcSnZh on 2021/5/9-下午7:21
*/
public class WorkerWrapperGroup {
/**
* 任务开始时间
*/
private final long groupStartTime;
/**
* 任务限时
*/
private final long timeoutLength;
/**
* 该map存放所有wrapper的id和wrapper映射
* <p/>
* 需要线程安全。
*/
private final Map<String, WorkerWrapper<?, ?>> forParamUseWrappers = new ConcurrentHashMap<>();
/**
* 当全部wrapper都调用结束它会countDown
*/
private final CountDownLatch endCDL = new CountDownLatch(1);
/**
* 检测到超时此标记变量将为true。
*/
private final AtomicBoolean anyTimeout = new AtomicBoolean(false);
/**
* 结束时间
*/
private volatile long finishTime = -1L;
/**
* 取消任务状态
* 0 - not cancel , 1 - waiting cancel , 2 - already cancel
*/
private final AtomicInteger cancelState = new AtomicInteger();
public static final int NOT_CANCEL = 0;
public static final int WAITING_CANCEL = 1;
public static final int ALREADY_CANCEL = 2;
public WorkerWrapperGroup(long groupStartTime, long timeoutLength) {
this.groupStartTime = groupStartTime;
this.timeoutLength = timeoutLength;
}
public void addWrapper(Collection<? extends WorkerWrapper<?, ?>> wrapper) {
Objects.requireNonNull(wrapper).forEach(this::addWrapper);
}
public void addWrapper(WorkerWrapper<?, ?>... wrappers) {
for (WorkerWrapper<?, ?> wrapper : Objects.requireNonNull(wrappers)) {
addWrapper(wrapper);
}
}
public void addWrapper(WorkerWrapper<?, ?> wrapper) {
if (wrapper != null) {
forParamUseWrappers.put(wrapper.id, wrapper);
}
}
public Map<String, WorkerWrapper<?, ?>> getForParamUseWrappers() {
return forParamUseWrappers;
}
public CountDownLatch getEndCDL() {
return endCDL;
}
public long getGroupStartTime() {
return groupStartTime;
}
public AtomicBoolean getAnyTimeout() {
return anyTimeout;
}
public long getFinishTime() {
return finishTime;
}
public boolean isCancelled() {
return cancelState.get() == ALREADY_CANCEL;
}
public boolean isWaitingCancel() {
return cancelState.get() == WAITING_CANCEL;
}
@SuppressWarnings("UnusedReturnValue")
public boolean pleaseCancel() {
return cancelState.compareAndSet(NOT_CANCEL, WAITING_CANCEL);
}
public class CheckFinishTask implements TimerTask {
@SuppressWarnings("RedundantThrows")
@Override
public void run(Timeout timeout) throws Exception {
// 已经完成了
if (endCDL.getCount() < 1) {
return;
}
AtomicBoolean hasTimeout = new AtomicBoolean(false);
// 记录正在运行中的wrapper里最近的限时时间。
final AtomicLong minDaley = new AtomicLong(Long.MAX_VALUE);
final Collection<WorkerWrapper<?, ?>> values = forParamUseWrappers.values();
final Stream<WorkerWrapper<?, ?>> stream = values.size() > 128 ? values.parallelStream() : values.stream();
final boolean needCancel = cancelState.get() == WAITING_CANCEL;
boolean allFinish_and_notNeedCancel = stream
// 需要取消的话就取消
.peek(wrapper -> {
if (needCancel) {
wrapper.cancel();
}
})
// 检查超时并保存最近一次限时时间
// 当需要取消时,才会不断遍历。如果不需要取消,则计算一次(或并行流中多次)就因allMatch不满足而退出了。
.peek(wrapper -> {
// time_diff :
// -1 -> already timeout ;
// 0 -> finish but not timeout ;
// X>0 -> is running , may timeout in X seconds .
long time_diff = wrapper.checkTimeout(true, groupStartTime, timeoutLength);
if (time_diff < 0) {
hasTimeout.set(true);
}
if (time_diff == 0) {
return;
}
// use CAS and SPIN for thread safety in parallelStream .
do {
long getMinDaley = minDaley.get();
// 需要设置最小时间但是cas失败则自旋
if (getMinDaley <= time_diff && !minDaley.compareAndSet(getMinDaley, time_diff)) {
continue;
}
return;
} while (true);
})
// 判断是否不需要取消且全部结束
// 在不需要取消时这里如果还有未结束的wrapper则会提前结束流并返回false
// 在需要取消时会全部遍历一遍并取消掉已经进入链路的wrapper
.allMatch(wrapper -> !needCancel && wrapper.getState().finished());
long getMinDaley = minDaley.get();
// 如果本次取消掉了任务或是所有wrapper都已经完成
// ( ps : 前后两条件在这里是必定 一真一假 或 两者全假 )
if (needCancel || allFinish_and_notNeedCancel) {
// 如果这次进行了取消,则设置取消状态为已完成
if (needCancel) {
cancelState.set(ALREADY_CANCEL);
}
anyTimeout.set(hasTimeout.get());
finishTime = SystemClock.now();
endCDL.countDown();
}
// 如果有正在运行的wrapper
else {
// 如果有正在WORKING的wrapper则计算一下限时时间限时完成后轮询它。
if (getMinDaley != Long.MAX_VALUE) {
PollingCenter.getInstance().checkGroup(this, getMinDaley);
}
}
}
// hashCode and equals will called WorkerWrapperGroup.this
/**
* 将会调用{@link WorkerWrapperGroup#hashCode()}
*/
@Override
public int hashCode() {
return WorkerWrapperGroup.this.hashCode();
}
/**
* 将会调用{@link WorkerWrapperGroup#equals(Object)}
*/
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof CheckFinishTask)) {
return false;
}
return Objects.equals(WorkerWrapperGroup.this, ((CheckFinishTask) obj).getParent());
}
private WorkerWrapperGroup getParent() {
return WorkerWrapperGroup.this;
}
}
}

View File

@@ -0,0 +1,135 @@
package com.jd.platform.async.wrapper.strategy;
import com.jd.platform.async.wrapper.WorkerWrapper;
import com.jd.platform.async.wrapper.strategy.depend.DependMustStrategyMapper;
import com.jd.platform.async.wrapper.strategy.depend.DependOnUpWrapperStrategyMapper;
import com.jd.platform.async.wrapper.strategy.depend.DependenceAction;
import com.jd.platform.async.wrapper.strategy.depend.DependenceStrategy;
import com.jd.platform.async.wrapper.strategy.skip.SkipStrategy;
import java.util.Set;
/**
* @author create by TcSnZh on 2021/5/17-下午6:23
*/
public interface WrapperStrategy extends DependenceStrategy, SkipStrategy {
// ========== 这三个策略器用于链式判断是否要开始工作 ==========
// 从前往后依次判断的顺序为 dependWrapperStrategyMapper -> dependMustStrategyMapper -> dependenceStrategy
/**
* 设置对特殊Wrapper专用的依赖响应策略。
*
* @return 该值允许为null
*/
DependOnUpWrapperStrategyMapper getDependWrapperStrategyMapper();
/**
* 对必须完成的must的Wrapper的依赖响应策略。
* 这是一个不得不向历史妥协的属性。用于适配must开关方式。
*
* @return 该值允许为null
* @deprecated 不推荐使用,很有可能被遗弃
*/
@SuppressWarnings("DeprecatedIsStillUsed")
@Deprecated
default DependMustStrategyMapper getDependMustStrategyMapper() {
return null;
}
/**
* 底层全局策略。
*
* @return 该值不允许为null
*/
DependenceStrategy getDependenceStrategy();
// ========== 这是跳过策略 ==========
/**
* 跳过策略
*
* @return 不允许为null
*/
SkipStrategy getSkipStrategy();
@Override
default DependenceAction.WithProperty judgeAction(Set<WorkerWrapper<?, ?>> dependWrappers,
WorkerWrapper<?, ?> thisWrapper,
WorkerWrapper<?, ?> fromWrapper) {
// 如果存在依赖,则调用三层依赖响应策略进行判断
DependenceStrategy strategy = getDependWrapperStrategyMapper();
if (getDependMustStrategyMapper() != null) {
strategy = strategy == null ? getDependMustStrategyMapper() : strategy.thenJudge(getDependenceStrategy());
}
if (getDependenceStrategy() != null) {
strategy = strategy == null ? getDependenceStrategy() : strategy.thenJudge(getDependenceStrategy());
}
if (strategy == null) {
throw new IllegalStateException("配置无效三层判断策略均为null请开发者检查自己的Builder是否逻辑错误");
}
return strategy.judgeAction(dependWrappers, thisWrapper, fromWrapper);
}
@Override
default boolean shouldSkip(Set<WorkerWrapper<?, ?>> nextWrappers, WorkerWrapper<?, ?> thisWrapper, WorkerWrapper<?, ?> fromWrapper) {
return getSkipStrategy() != null && getSkipStrategy().shouldSkip(nextWrappers, thisWrapper, fromWrapper);
}
default void setDependWrapperStrategyMapper(DependOnUpWrapperStrategyMapper dependOnUpWrapperStrategyMapper) {
throw new UnsupportedOperationException();
}
default void setDependMustStrategyMapper(DependMustStrategyMapper dependMustStrategyMapper) {
throw new UnsupportedOperationException();
}
default void setDependenceStrategy(DependenceStrategy dependenceStrategy) {
throw new UnsupportedOperationException();
}
default void setSkipStrategy(SkipStrategy skipStrategy) {
throw new UnsupportedOperationException();
}
/**
* 抽象策略器实现了toString
*/
abstract class AbstractWrapperStrategy implements WrapperStrategy {
@Override
public String toString() {
return "WrapperStrategy{" +
"dependWrapperStrategyMapper=" + getDependWrapperStrategyMapper() +
", dependMustStrategyMapper=" + getDependMustStrategyMapper() +
", dependenceStrategy=" + getDependenceStrategy() +
", skipStrategy=" + getSkipStrategy() +
'}';
}
}
/**
* 默认策略器,用默认值实现了所有属性。
*/
class DefaultWrapperStrategy extends AbstractWrapperStrategy {
@Override
public DependOnUpWrapperStrategyMapper getDependWrapperStrategyMapper() {
return null;
}
@Override
public DependMustStrategyMapper getDependMustStrategyMapper() {
return null;
}
@Override
public DependenceStrategy getDependenceStrategy() {
return DependenceStrategy.ALL_DEPENDENCIES_ALL_SUCCESS;
}
@Override
public SkipStrategy getSkipStrategy() {
return SkipStrategy.CHECK_ONE_LEVEL;
}
}
}

View File

@@ -1,4 +1,4 @@
package com.jd.platform.async.wrapper.actionstrategy;
package com.jd.platform.async.wrapper.strategy.depend;
import com.jd.platform.async.worker.ResultState;
import com.jd.platform.async.wrapper.WorkerWrapper;
@@ -26,7 +26,7 @@ public class DependMustStrategyMapper implements DependenceStrategy {
* 如果所有的Wrapper已经完成本Wrapper将会开始工作
* <p>
* 如果任一{@link #mustDependSet}中的Wrapper失败则返回{@link DependenceAction#FAST_FAIL}
* 具体超时/异常则根据{@link com.jd.platform.async.worker.ResultState}的值进行判断
* 具体超时/异常则根据{@link ResultState}的值进行判断
* <p>
* 如果存在Wrapper未完成 所有的Wrapper都未失败则返回{@link DependenceAction#JUDGE_BY_AFTER}
* </p>

View File

@@ -1,16 +1,16 @@
package com.jd.platform.async.wrapper.actionstrategy;
package com.jd.platform.async.wrapper.strategy.depend;
import com.jd.platform.async.wrapper.WorkerWrapper;
/**
* 单参数策略
* 由上游wrapper决定本wrapper行为的单参数策略
*
* @author create by TcSnZh on 2021/5/1-下午11:16
*/
@FunctionalInterface
public interface DependWrapperActionStrategy {
public interface DependOnUpWrapperStrategy {
/**
* 仅使用一个参数的判断方法
* 仅使用一个参数即调用自身的上游wrapper的判断方法
*
* @param fromWrapper 调用本Wrapper的上游Wrapper
* @return 返回 {@link DependenceAction.WithProperty}
@@ -24,7 +24,7 @@ public interface DependWrapperActionStrategy {
* 未运行时休息
* 失败时失败
*/
DependWrapperActionStrategy SUCCESS_CONTINUE = new DependWrapperActionStrategy() {
DependOnUpWrapperStrategy SUCCESS_CONTINUE = new DependOnUpWrapperStrategy() {
@Override
public DependenceAction.WithProperty judge(WorkerWrapper<?, ?> ww) {
switch (ww.getWorkResult().getResultState()) {
@@ -50,7 +50,7 @@ public interface DependWrapperActionStrategy {
* 未运行时交给下一个策略器判断
* 失败时失败
*/
DependWrapperActionStrategy SUCCESS_START_INIT_CONTINUE = new DependWrapperActionStrategy() {
DependOnUpWrapperStrategy SUCCESS_START_INIT_CONTINUE = new DependOnUpWrapperStrategy() {
@Override
public DependenceAction.WithProperty judge(WorkerWrapper<?, ?> ww) {
switch (ww.getWorkResult().getResultState()) {

View File

@@ -1,4 +1,4 @@
package com.jd.platform.async.wrapper.actionstrategy;
package com.jd.platform.async.wrapper.strategy.depend;
import com.jd.platform.async.wrapper.WorkerWrapper;
@@ -10,12 +10,12 @@ import java.util.stream.Collectors;
/**
* 对不同的{@link WorkerWrapper}调用者实行个性化依赖响应策略
* <p/>
* 使用{@link DependWrapperStrategyMapper}本实现类对{@link DependenceStrategy}进行增强
* 使用{@link DependOnUpWrapperStrategyMapper}本实现类对{@link DependenceStrategy}进行增强
*
* @author create by TcSnZh on 2021/5/1-下午11:12
*/
public class DependWrapperStrategyMapper implements DependenceStrategy {
private final Map<WorkerWrapper<?, ?>, DependWrapperActionStrategy> mapper = new ConcurrentHashMap<>(4);
public class DependOnUpWrapperStrategyMapper implements DependenceStrategy {
private final Map<WorkerWrapper<?, ?>, DependOnUpWrapperStrategy> mapper = new ConcurrentHashMap<>(4);
/**
* 设置对应策略
@@ -24,7 +24,8 @@ public class DependWrapperStrategyMapper implements DependenceStrategy {
* @param strategy 要设置的策略
* @return 返回this链式调用
*/
public DependWrapperStrategyMapper putMapping(WorkerWrapper<?, ?> targetWrapper, DependWrapperActionStrategy strategy) {
@SuppressWarnings("UnusedReturnValue")
public DependOnUpWrapperStrategyMapper putMapping(WorkerWrapper<?, ?> targetWrapper, DependOnUpWrapperStrategy strategy) {
mapper.put(targetWrapper, strategy);
toStringCache = null;
return this;
@@ -33,7 +34,7 @@ public class DependWrapperStrategyMapper implements DependenceStrategy {
/**
* 判断方法
* <p/>
* 如果fromWrapper在{@link #mapper}则返回{@link DependWrapperActionStrategy}的判断返回值否则返回{@link DependenceAction#JUDGE_BY_AFTER}
* 如果fromWrapper在{@link #mapper}则返回{@link DependOnUpWrapperStrategy}的判断返回值否则返回{@link DependenceAction#JUDGE_BY_AFTER}
*
* @param dependWrappers 这里不会使用该值thisWrapper.dependWrappers的属性值
* @param thisWrapper 这里不会使用该值thisWrapper即为被催促的WorkerWrapper
@@ -44,7 +45,7 @@ public class DependWrapperStrategyMapper implements DependenceStrategy {
public DependenceAction.WithProperty judgeAction(Set<WorkerWrapper<?,?>> dependWrappers,
WorkerWrapper<?, ?> thisWrapper,
WorkerWrapper<?, ?> fromWrapper) {
DependWrapperActionStrategy strategy = mapper.get(fromWrapper);
DependOnUpWrapperStrategy strategy = mapper.get(fromWrapper);
if (strategy == null) {
return DependenceAction.JUDGE_BY_AFTER.emptyProperty();
}

View File

@@ -1,4 +1,4 @@
package com.jd.platform.async.wrapper.actionstrategy;
package com.jd.platform.async.wrapper.strategy.depend;
import com.jd.platform.async.worker.ResultState;
@@ -13,7 +13,7 @@ public enum DependenceAction {
*/
START_WORK,
/**
* 还没轮到休息一下WorkerWrapper中的调用栈会返回以等待可能发生的下次调用
* 还没轮到休息一下WorkerWrapper中的调用栈会返回以等待其他上游wrapper调用它或是会一生无缘被调用
*/
TAKE_REST,
/**
@@ -22,6 +22,8 @@ public enum DependenceAction {
FAST_FAIL,
/**
* 交给下层{@link DependenceStrategy}进行判断
* 由于{@link DependenceStrategy#thenJudge(DependenceStrategy)}的责任链设计模式该返回值的意义就是调用责任链上下一个策略
* <p/>
* 在WorkerWrapper中不需要考虑此值因为配置正常的情况下不会返回这个值
*/
JUDGE_BY_AFTER;
@@ -29,6 +31,10 @@ public enum DependenceAction {
// 空值单例
public WithProperty emptyProperty() {
if (this == FAST_FAIL) {
throw new UnsupportedOperationException(
"配置错误: FAST_FAIL 不能使用该方法请使用fastFailException(ResultState, Exception)具体设置fastFail的参数。");
}
return empty;
}
@@ -66,6 +72,9 @@ public enum DependenceAction {
* 所有的构造方法权限均为private请在父枚举类{@link DependenceAction}的方法中选择合适的模板生成内部类WithProperty
*/
public class WithProperty {
/**
* 以下两个属性用于设置fastFail的属性
*/
private ResultState resultState;
private Exception fastFailException;

View File

@@ -1,11 +1,13 @@
package com.jd.platform.async.wrapper.actionstrategy;
package com.jd.platform.async.wrapper.strategy.depend;
import com.jd.platform.async.wrapper.WrapperEndingInspector;
import com.jd.platform.async.exception.SkippedException;
import com.jd.platform.async.worker.ResultState;
import com.jd.platform.async.worker.WorkResult;
import com.jd.platform.async.wrapper.WorkerWrapper;
import com.jd.platform.async.wrapper.WorkerWrapperGroup;
import java.util.*;
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.stream.Collectors;
@@ -36,12 +38,12 @@ public interface DependenceStrategy {
* @param fromWrapper 调用来源Wrapper
* <p>
* 该参数不会为null
* 因为在{@link WorkerWrapper#work(ExecutorService, long, Map, WrapperEndingInspector)}方法中传入的的第一批无依赖的Wrapper
* 因为在{@link WorkerWrapper#work(ExecutorService, long, WorkerWrapperGroup)}方法中传入的的第一批无依赖的Wrapper
* 不会被该策略器所判断而是不论如何直接执行
* </p>
* @return 返回枚举值内部类WorkerWrapper将会根据其值来决定自己如何响应这次调用 {@link DependenceAction.WithProperty}
*/
DependenceAction.WithProperty judgeAction(Set<WorkerWrapper<?,?>> dependWrappers,
DependenceAction.WithProperty judgeAction(Set<WorkerWrapper<?, ?>> dependWrappers,
WorkerWrapper<?, ?> thisWrapper,
WorkerWrapper<?, ?> fromWrapper);
@@ -55,7 +57,7 @@ public interface DependenceStrategy {
DependenceStrategy that = this;
return new DependenceStrategy() {
@Override
public DependenceAction.WithProperty judgeAction(Set<WorkerWrapper<?,?>> dependWrappers,
public DependenceAction.WithProperty judgeAction(Set<WorkerWrapper<?, ?>> dependWrappers,
WorkerWrapper<?, ?> thisWrapper,
WorkerWrapper<?, ?> fromWrapper) {
DependenceAction.WithProperty judge = that.judgeAction(dependWrappers, thisWrapper, fromWrapper);
@@ -81,7 +83,7 @@ public interface DependenceStrategy {
*/
DependenceStrategy ALL_DEPENDENCIES_ALL_SUCCESS = new DependenceStrategy() {
@Override
public DependenceAction.WithProperty judgeAction(Set<WorkerWrapper<?,?>> dependWrappers,
public DependenceAction.WithProperty judgeAction(Set<WorkerWrapper<?, ?>> dependWrappers,
WorkerWrapper<?, ?> thisWrapper,
WorkerWrapper<?, ?> fromWrapper) {
boolean hasWaiting = false;
@@ -119,7 +121,7 @@ public interface DependenceStrategy {
*/
DependenceStrategy ALL_DEPENDENCIES_ANY_SUCCESS = new DependenceStrategy() {
@Override
public DependenceAction.WithProperty judgeAction(Set<WorkerWrapper<?,?>> dependWrappers,
public DependenceAction.WithProperty judgeAction(Set<WorkerWrapper<?, ?>> dependWrappers,
WorkerWrapper<?, ?> thisWrapper,
WorkerWrapper<?, ?> fromWrapper) {
boolean hasFailed = false;
@@ -136,6 +138,7 @@ public interface DependenceStrategy {
case EXCEPTION:
resultState = !hasFailed ? workResult.getResultState() : resultState;
fastFailException = !hasFailed ? workResult.getEx() : fastFailException;
// 跳过不算失败
hasFailed = true;
break;
default:
@@ -155,11 +158,13 @@ public interface DependenceStrategy {
};
/**
* 如果被依赖的工作中任一失败则立即失败否则就开始工作不论之前的工作有没有开始
* 如果被依赖的工作中任一失败则立即失败
* 否则就开始工作不论之前的工作有没有开始
*/
@SuppressWarnings("unused")
DependenceStrategy ALL_DEPENDENCIES_NONE_FAILED = new DependenceStrategy() {
@Override
public DependenceAction.WithProperty judgeAction(Set<WorkerWrapper<?,?>> dependWrappers,
public DependenceAction.WithProperty judgeAction(Set<WorkerWrapper<?, ?>> dependWrappers,
WorkerWrapper<?, ?> thisWrapper,
WorkerWrapper<?, ?> fromWrapper) {
for (WorkerWrapper<?, ?> dependWrapper : dependWrappers) {
@@ -167,7 +172,7 @@ public interface DependenceStrategy {
switch (workResult.getResultState()) {
case TIMEOUT:
case EXCEPTION:
return DependenceAction.FAST_FAIL.fastFailException(workResult.getResultState(), workResult.getEx());
return DependenceAction.FAST_FAIL.fastFailException(workResult.getResultState(), workResult.getEx());
default:
}
}
@@ -188,7 +193,8 @@ public interface DependenceStrategy {
* @param theseWrapper 该方法唯一有效参数
* @return 返回生成的 {@link DependenceAction.WithProperty)
*/
static DependenceStrategy theseWrapperAllSuccess(Set<WorkerWrapper<?,?>> theseWrapper) {
@SuppressWarnings("unused")
static DependenceStrategy theseWrapperAllSuccess(Set<WorkerWrapper<?, ?>> theseWrapper) {
return new DependenceStrategy() {
private final Set<WorkerWrapper<?, ?>> theseWrappers;
private final String toString;
@@ -199,7 +205,7 @@ public interface DependenceStrategy {
}
@Override
public DependenceAction.WithProperty judgeAction(Set<WorkerWrapper<?,?>> dependWrappers,
public DependenceAction.WithProperty judgeAction(Set<WorkerWrapper<?, ?>> dependWrappers,
WorkerWrapper<?, ?> thisWrapper,
WorkerWrapper<?, ?> fromWrapper) {
boolean hasWaiting = false;
@@ -232,7 +238,17 @@ public interface DependenceStrategy {
};
}
DependenceStrategy IF_MUST_SET_NOT_EMPTY_ALL_SUCCESS_ELSE_ANY = new DependenceStrategy() {
/**
* 此值用于适配v1.4及之前的must开关模式
* `wrapperStrategy``dependMustStrategyMapper``mustDependSet`不为空时
* 则休息因为能判断到这个责任链说明set中存在不满足的值L
* 为空时则任一成功则执行
*
* @deprecated 不推荐使用must开关
*/
@SuppressWarnings("DeprecatedIsStillUsed")
@Deprecated
DependenceStrategy IF_MUST_SET_NOT_EMPTY_ALL_SUCCESS_ELSE_ANY = new DependenceStrategy() {
@Override
public DependenceAction.WithProperty judgeAction(Set<WorkerWrapper<?, ?>> dependWrappers,
WorkerWrapper<?, ?> thisWrapper,

View File

@@ -0,0 +1,53 @@
package com.jd.platform.async.wrapper.strategy.skip;
import com.jd.platform.async.wrapper.WorkerWrapper;
import java.util.Set;
/**
* @author create by TcSnZh on 2021/5/6-下午3:02
*/
@FunctionalInterface
public interface SkipStrategy {
/**
* 跳过策略函数。返回true将会使WorkerWrapper跳过执行。
*
* @param nextWrappers 下游WrapperSet
* @param thisWrapper 本WorkerWrapper
* @param fromWrapper 呼叫本Wrapper的上游Wrapper
* @return 返回true将会使WorkerWrapper跳过执行。
*/
boolean shouldSkip(Set<WorkerWrapper<?, ?>> nextWrappers, WorkerWrapper<?, ?> thisWrapper, WorkerWrapper<?, ?> fromWrapper);
/**
* 不跳过
*/
SkipStrategy NOT_SKIP = new SkipStrategy() {
@Override
public boolean shouldSkip(Set<WorkerWrapper<?, ?>> nextWrappers, WorkerWrapper<?, ?> thisWrapper, WorkerWrapper<?, ?> fromWrapper) {
return false;
}
@Override
public String toString() {
return "NOT_SKIP";
}
};
/**
* 距离为1的wrapper都不在初始化状态
*/
SkipStrategy CHECK_ONE_LEVEL = new SkipStrategy() {
@Override
public boolean shouldSkip(Set<WorkerWrapper<?, ?>> nextWrappers, WorkerWrapper<?, ?> thisWrapper, WorkerWrapper<?, ?> fromWrapper) {
return nextWrappers != null && !nextWrappers.isEmpty()
&& nextWrappers.stream().allMatch(workerWrapper -> workerWrapper.getState().finished());
}
@Override
public String toString() {
return "CHECK_ONE_LEVEL";
}
};
}

View File

@@ -14,7 +14,7 @@ import java.util.Map;
class DeWorker implements IWorker<String, User>, ICallback<String, User> {
@Override
public User action(String object, Map<String, WorkerWrapper> allWrappers) {
public User action(String object, Map<String, WorkerWrapper<?,?>> allWrappers) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {

View File

@@ -14,7 +14,7 @@ import java.util.Map;
class DeWorker1 implements IWorker<WorkResult<User>, User>, ICallback<WorkResult<User>, User> {
@Override
public User action(WorkResult<User> result, Map<String, WorkerWrapper> allWrappers) {
public User action(WorkResult<User> result, Map<String, WorkerWrapper<?,?>> allWrappers) {
System.out.println("par1的入参来自于par0 " + result.getResult());
try {
Thread.sleep(1000);

View File

@@ -14,7 +14,7 @@ import java.util.Map;
class DeWorker2 implements IWorker<WorkResult<User>, String>, ICallback<WorkResult<User>, String> {
@Override
public String action(WorkResult<User> result, Map<String, WorkerWrapper> allWrappers) {
public String action(WorkResult<User> result, Map<String, WorkerWrapper<?,?>> allWrappers) {
System.out.println("par2的入参来自于par1 " + result.getResult());
try {
Thread.sleep(1000);

View File

@@ -10,10 +10,11 @@ import com.jd.platform.async.wrapper.WorkerWrapper;
* @author sjsdfg
* @since 2020/6/14
*/
@SuppressWarnings({"deprecation", "RedundantStringFormatCall"})
class LambdaTest {
public static void main(String[] args) throws Exception {
WorkerWrapper<WorkResult<User>, String> workerWrapper2 = new WorkerWrapper.Builder<WorkResult<User>, String>()
.worker((WorkResult<User> result, Map<String, WorkerWrapper> allWrappers) -> {
.worker((WorkResult<User> result, Map<String, WorkerWrapper<?, ?>> allWrappers) -> {
System.out.println("par2的入参来自于par1 " + result.getResult());
try {
Thread.sleep(1000);
@@ -28,7 +29,7 @@ class LambdaTest {
.build();
WorkerWrapper<WorkResult<User>, User> workerWrapper1 = new WorkerWrapper.Builder<WorkResult<User>, User>()
.worker((WorkResult<User> result, Map<String, WorkerWrapper> allWrappers) -> {
.worker((WorkResult<User> result, Map<String, WorkerWrapper<?, ?>> allWrappers) -> {
System.out.println("par1的入参来自于par0 " + result.getResult());
try {
Thread.sleep(1000);
@@ -44,7 +45,7 @@ class LambdaTest {
.build();
WorkerWrapper<String, User> workerWrapper = new WorkerWrapper.Builder<String, User>()
.worker((String object, Map<String, WorkerWrapper> allWrappers) -> {
.worker((String object, Map<String, WorkerWrapper<?,?>> allWrappers) -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {

View File

@@ -14,7 +14,7 @@ import java.util.Map;
class DeWorker implements IWorker<String, User>, ICallback<String, User> {
@Override
public User action(String object, Map<String, WorkerWrapper> allWrappers) {
public User action(String object, Map<String, WorkerWrapper<?,?>> allWrappers) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {

View File

@@ -14,7 +14,7 @@ import java.util.Map;
class DeWorker1 implements IWorker<String, User>, ICallback<String, User> {
@Override
public User action(String object, Map<String, WorkerWrapper> allWrappers) {
public User action(String object, Map<String, WorkerWrapper<?,?>> allWrappers) {
System.out.println("-----------------");
System.out.println("获取par0的执行结果 " + allWrappers.get("first").getWorkResult());
System.out.println("取par0的结果作为自己的入参并将par0的结果加上一些东西");

View File

@@ -14,7 +14,7 @@ import java.util.Map;
class DeWorker2 implements IWorker<User, String>, ICallback<User, String> {
@Override
public String action(User object, Map<String, WorkerWrapper> allWrappers) {
public String action(User object, Map<String, WorkerWrapper<?,?>> allWrappers) {
System.out.println("-----------------");
System.out.println("par1的执行结果是 " + allWrappers.get("second").getWorkResult());
System.out.println("取par1的结果作为自己的入参并将par1的结果加上一些东西");

View File

@@ -15,7 +15,7 @@ import java.util.Map;
class ParTimeoutWorker implements IWorker<String, String>, ICallback<String, String> {
@Override
public String action(String object, Map<String, WorkerWrapper> allWrappers) {
public String action(String object, Map<String, WorkerWrapper<?,?>> allWrappers) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {

View File

@@ -15,7 +15,7 @@ import java.util.Map;
class ParWorker implements IWorker<String, String>, ICallback<String, String> {
@Override
public String action(String object, Map<String, WorkerWrapper> allWrappers) {
public String action(String object, Map<String, WorkerWrapper<?,?>> allWrappers) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {

View File

@@ -20,7 +20,7 @@ class ParWorker1 implements IWorker<String, String>, ICallback<String, String> {
}
@Override
public String action(String object, Map<String, WorkerWrapper> allWrappers) {
public String action(String object, Map<String, WorkerWrapper<?,?>> allWrappers) {
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {

View File

@@ -20,7 +20,7 @@ class ParWorker2 implements IWorker<String, String>, ICallback<String, String> {
}
@Override
public String action(String object, Map<String, WorkerWrapper> allWrappers) {
public String action(String object, Map<String, WorkerWrapper<?,?>> allWrappers) {
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {

View File

@@ -19,7 +19,7 @@ class ParWorker3 implements IWorker<String, String>, ICallback<String, String> {
this.sleepTime = sleepTime;
}
@Override
public String action(String object, Map<String, WorkerWrapper> allWrappers) {
public String action(String object, Map<String, WorkerWrapper<?,?>> allWrappers) {
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {

View File

@@ -15,7 +15,7 @@ import java.util.Map;
class ParWorker4 implements IWorker<String, String>, ICallback<String, String> {
@Override
public String action(String object, Map<String, WorkerWrapper> allWrappers) {
public String action(String object, Map<String, WorkerWrapper<?,?>> allWrappers) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {

View File

@@ -15,7 +15,7 @@ import java.util.Map;
class SeqTimeoutWorker implements IWorker<String, String>, ICallback<String, String> {
@Override
public String action(String object, Map<String, WorkerWrapper> allWrappers) {
public String action(String object, Map<String, WorkerWrapper<?,?>> allWrappers) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {

View File

@@ -15,7 +15,7 @@ import java.util.Map;
class SeqWorker implements IWorker<String, String>, ICallback<String, String> {
@Override
public String action(String object, Map<String, WorkerWrapper> allWrappers) {
public String action(String object, Map<String, WorkerWrapper<?,?>> allWrappers) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {

View File

@@ -15,7 +15,7 @@ import java.util.Map;
class SeqWorker1 implements IWorker<String, String>, ICallback<String, String> {
@Override
public String action(String object, Map<String, WorkerWrapper> allWrappers) {
public String action(String object, Map<String, WorkerWrapper<?,?>> allWrappers) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {

View File

@@ -15,7 +15,7 @@ import java.util.Map;
class SeqWorker2 implements IWorker<String, String>, ICallback<String, String> {
@Override
public String action(String object, Map<String, WorkerWrapper> allWrappers) {
public String action(String object, Map<String, WorkerWrapper<?,?>> allWrappers) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {

View File

@@ -0,0 +1,37 @@
package v15.cases;
import com.jd.platform.async.executor.Async;
import com.jd.platform.async.wrapper.WorkerWrapper;
import com.jd.platform.async.wrapper.WorkerWrapperBuilder;
import java.util.concurrent.ExecutionException;
/**
* @author tcsnzh[zh.jobs@foxmail.com] create this in 2021/5/25-下午9:10
*/
class Case0 {
static WorkerWrapperBuilder<?, ?> builder(String id) {
return WorkerWrapper.<String, String>builder()
.id(id)
.worker((param, allWrappers) -> {
System.out.println("wrapper(id=" + id + ") is working");
return null;
});
}
public static void main(String[] args) {
WorkerWrapper<?, ?> a = builder("A").build();
WorkerWrapper<?, ?> b = builder("B").build();
WorkerWrapper<?, ?> c = builder("C").build();
try {
Async.work(100, a, b, c).awaitFinish();
} catch (InterruptedException e) {
e.printStackTrace();
}
/* 输出:
wrapper(id=A) is working
wrapper(id=B) is working
wrapper(id=C) is working
*/
}
}

View File

@@ -0,0 +1,37 @@
package v15.cases;
import com.jd.platform.async.executor.Async;
import com.jd.platform.async.wrapper.WorkerWrapper;
import com.jd.platform.async.wrapper.WorkerWrapperBuilder;
/**
* @author tcsnzh[zh.jobs@foxmail.com] create this in 2021/5/25-下午9:13
*/
class Case01 {
static WorkerWrapperBuilder<?, ?> builder(String id) {
return WorkerWrapper.<String, String>builder()
.id(id)
.worker((param, allWrappers) -> {
System.out.println("wrapper(id=" + id + ") is working");
return null;
});
}
public static void main(String[] args) {
WorkerWrapper<?, ?> a = builder("A").build();
WorkerWrapper<?, ?> b = builder("B").depends(a).build();
WorkerWrapper<?, ?> c = builder("C").depends(a).build();
WorkerWrapper<?, ?> f = builder("F").depends(b, c).build();
try {
Async.work(100, a).awaitFinish();
} catch (InterruptedException e) {
e.printStackTrace();
}
/* 输出:
wrapper(id=A) is working
wrapper(id=C) is working
wrapper(id=B) is working
wrapper(id=F) is working
*/
}
}

View File

@@ -0,0 +1,38 @@
package v15.cases;
import com.jd.platform.async.executor.Async;
import com.jd.platform.async.wrapper.WorkerWrapper;
import com.jd.platform.async.wrapper.WorkerWrapperBuilder;
/**
* @author tcsnzh[zh.jobs@foxmail.com] create this in 2021/5/25-下午9:15
*/
class Case02 {
static WorkerWrapperBuilder<?, ?> builder(String id) {
return WorkerWrapper.<String, String>builder()
.id(id)
.worker((param, allWrappers) -> {
System.out.println("wrapper(id=" + id + ") is working");
return null;
});
}
public static void main(String[] args) {
WorkerWrapper<?, ?> f = builder("F").build();
WorkerWrapper<?, ?> a = builder("A")
.nextOf(builder("B").nextOf(f).build())
.nextOf(builder("C").nextOf(f).build())
.build();
try {
Async.work(100, a).awaitFinish();
} catch (InterruptedException e) {
e.printStackTrace();
}
/* 输出:
wrapper(id=A) is working
wrapper(id=B) is working
wrapper(id=C) is working
wrapper(id=F) is working
*/
}
}

View File

@@ -0,0 +1,62 @@
package v15.cases;
import com.jd.platform.async.executor.Async;
import com.jd.platform.async.wrapper.WorkerWrapper;
import com.jd.platform.async.wrapper.WorkerWrapperBuilder;
import java.util.concurrent.ExecutionException;
/**
* 示例:简单示例--复杂点的
*
* @author create by TcSnZh on 2021/5/8-下午10:29
*/
class Case1 {
private static WorkerWrapperBuilder<?, ?> builder(String id) {
return WorkerWrapper.<String, String>builder()
.id(id)
.worker((param, allWrappers) -> {
System.out.println("wrapper(id=" + id + ") is working");
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
});
}
public static void main(String[] args) {
WorkerWrapper<?, ?> a = builder("A").build();
WorkerWrapper<?, ?> d;
builder("H")
.depends(
builder("F")
.depends(builder("B").depends(a).build())
.depends(builder("C").depends(a).build())
.build(),
builder("G")
.depends(builder("E")
.depends(d = builder("D").build())
.build())
.build()
)
.build();
try {
Async.work(1000, a, d).awaitFinish();
} catch (InterruptedException e) {
e.printStackTrace();
}
/* 输出:
wrapper(id=D) is working
wrapper(id=A) is working
wrapper(id=E) is working
wrapper(id=B) is working
wrapper(id=C) is working
wrapper(id=G) is working
wrapper(id=F) is working
wrapper(id=H) is working
*/
}
}

View File

@@ -0,0 +1,72 @@
package v15.cases;
import com.jd.platform.async.callback.ICallback;
import com.jd.platform.async.executor.Async;
import com.jd.platform.async.worker.OnceWork;
import com.jd.platform.async.worker.WorkResult;
import com.jd.platform.async.wrapper.WorkerWrapper;
import com.jd.platform.async.wrapper.WorkerWrapperBuilder;
import java.util.concurrent.ExecutionException;
/**
* @author tcsnzh[zh.jobs@foxmail.com] create this in 2021/5/26-下午4:07
*/
class Case10 {
private static WorkerWrapperBuilder<?, ?> builder(String id) {
return builder(id, -1L);
}
private static WorkerWrapperBuilder<?, ?> builder(String id, long sleepTime) {
return WorkerWrapper.<String, String>builder()
.id(id)
.worker((param, allWrappers) -> {
System.out.println("\twrapper(id=" + id + ") is working");
if (sleepTime > 0) {
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return null;
})
.callback((new ICallback<String, String>() {
@Override
public void begin() {
System.out.println("wrapper(id=" + id + ") has begin . ");
}
@Override
public void result(boolean success, String param, WorkResult<String> workResult) {
System.out.println("\t\twrapper(id=" + id + ") callback "
+ (success ? "success " : "fail ")
+ ", workResult is " + workResult);
}
}))
.allowInterrupt(true);
}
/**
* A(10ms) ==> B(10ms) ==> C(10ms)
*/
public static void main(String[] args) throws ExecutionException, InterruptedException {
final WorkerWrapper<?, ?> c;
final WorkerWrapper<?, ?> b;
final WorkerWrapper<?, ?> a = builder("A", 10)
.nextOf(b = builder("B", 10)
.nextOf(c = builder("C", 10).build())
.build())
.build();
final OnceWork onceWork = Async.work(40, a);
Thread.sleep(25);
onceWork.pleaseCancelAndAwaitFinish();
System.out.println("任务b信息 " + b);
System.out.println("任务c信息 " + c);
System.out.println("OnceWork信息 " + onceWork);
/*
可以看到C的state为SKIPworkResult.ex为CancelSkippedException即被取消了。
不过有时程序运行慢导致B被取消了那么C就不会执行其状态就为INIT了。
*/
}
}

View File

@@ -0,0 +1,53 @@
package v15.cases;
import com.jd.platform.async.callback.IWorker;
import com.jd.platform.async.executor.Async;
import com.jd.platform.async.wrapper.WorkerWrapper;
import java.util.Map;
import java.util.concurrent.ExecutionException;
/**
* 示例:简单示例--依赖别的worker执行结果作为入参
*
* @author create by TcSnZh on 2021/5/8-下午10:46
*/
class Case2 {
static class AddWork implements IWorker<Integer, Integer> {
private final String id1;
private final String id2;
public AddWork(String id1, String id2) {
this.id1 = id1;
this.id2 = id2;
}
public AddWork() {
this(null, null);
}
@Override
public Integer action(Integer param, Map<String, WorkerWrapper<?,?>> allWrappers) {
// 传入的参数
if (param != null) {
return param;
}
// 将两个id所对应的wrapper的结果取出相加并返回
Integer i1 = (Integer) allWrappers.get(id1).getWorkResult().getResult();
Integer i2 = (Integer) allWrappers.get(id2).getWorkResult().getResult();
return i1 + i2;
}
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
WorkerWrapper<Integer, Integer> wrapper100 = WorkerWrapper.<Integer, Integer>builder()
.id("id:100").worker(new AddWork()).param(100).build();
WorkerWrapper<Integer, Integer> wrapper200 = WorkerWrapper.<Integer, Integer>builder()
.id("id:200").worker(new AddWork()).param(200).build();
WorkerWrapper<Integer, Integer> add = WorkerWrapper.<Integer, Integer>builder().id("id:add")
.worker(new AddWork("id:100", "id:200")).depends(wrapper100, wrapper200).build();
Async.work(20,wrapper100,wrapper200).awaitFinish();
System.out.println(add.getWorkResult());
// 输出WorkResult{result=300, resultState=SUCCESS, ex=null}
}
}

View File

@@ -0,0 +1,63 @@
package v15.cases;
import com.jd.platform.async.executor.Async;
import com.jd.platform.async.wrapper.WorkerWrapper;
import com.jd.platform.async.wrapper.WorkerWrapperBuilder;
import com.jd.platform.async.wrapper.strategy.depend.DependenceStrategy;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 示例:设置依赖策略--快速上手
*
* @author create by TcSnZh on 2021/5/8-下午10:58
*/
class Case3 {
private static WorkerWrapperBuilder<?, ?> builder(String id) {
return WorkerWrapper.<String, String>builder()
.id(id)
.worker((param, allWrappers) -> {
System.out.println("wrapper(id=" + id + ") is working");
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
});
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
WorkerWrapper<?, ?> a = builder("A").build();
WorkerWrapper<?, ?> b1 = builder("B1").depends(a).build();
WorkerWrapper<?, ?> b2 = builder("B2").depends(a).build();
WorkerWrapper<?, ?> b3 = builder("B3").depends(a).build();
WorkerWrapper<?, ?> b4 = builder("B4").depends(a).build();
WorkerWrapper<?, ?> b5 = builder("B5").depends(a).build();
WorkerWrapper<?, ?> c1 = builder("C1")
.depends(DependenceStrategy.ALL_DEPENDENCIES_ALL_SUCCESS, b1, b2)
.build();
WorkerWrapper<?, ?> c2 = builder("C2")
.depends(DependenceStrategy.ALL_DEPENDENCIES_ANY_SUCCESS, b3, b4, b5)
.build();
// 这里用线程数较少的线程池做示例对于ALL_DEPENDENCIES_ANY_SUCCESS“仅需一个”的效果会好一点
ExecutorService pool = Executors.newFixedThreadPool(2);
try {
Async.work(1000, pool, a).awaitFinish();
} finally {
pool.shutdown();
}
/* 输出:
wrapper(id=A) is working
wrapper(id=B3) is working
wrapper(id=B1) is working
wrapper(id=B2) is working
wrapper(id=C2) is working
wrapper(id=C1) is working
wrapper(id=B4) is working
// 我们看到B5被跳过了没有执行callback
*/
}
}

View File

@@ -0,0 +1,69 @@
package v15.cases;
import com.jd.platform.async.executor.Async;
import com.jd.platform.async.worker.ResultState;
import com.jd.platform.async.wrapper.WorkerWrapper;
import com.jd.platform.async.wrapper.WorkerWrapperBuilder;
import com.jd.platform.async.wrapper.strategy.depend.DependenceAction;
import com.jd.platform.async.wrapper.strategy.depend.DependenceStrategy;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 示例:自定义全局策略
*
* @author create by TcSnZh on 2021/5/8-下午11:28
*/
class Case4 {
private static WorkerWrapperBuilder<?, ?> builder(String id) {
return WorkerWrapper.<String, String>builder()
.id(id)
.worker((param, allWrappers) -> {
System.out.println("wrapper(id=" + id + ") is working");
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
});
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
WorkerWrapper<?, ?> a = builder("A").build();
WorkerWrapper<?, ?> c = builder("C")
.setDepend().strategy(new DependenceStrategy() {
@Override
public DependenceAction.WithProperty judgeAction(Set<WorkerWrapper<?, ?>> dependWrappers, WorkerWrapper<?, ?> thisWrapper, WorkerWrapper<?, ?> fromWrapper) {
return dependWrappers.stream()
.filter(workerWrapper -> workerWrapper.getWorkResult().getResultState() == ResultState.SUCCESS)
.count() > 3 ?
DependenceAction.START_WORK.emptyProperty()
: DependenceAction.TAKE_REST.emptyProperty();
}
}).end()
.build();
for (int i = 1; i < 10; i++) {
builder("B" + i).depends(a).nextOf(c).build();
}
ExecutorService pool = Executors.newFixedThreadPool(2);
try {
Async.work(1000, pool, a).awaitFinish();
} finally {
pool.shutdown();
}
/* 输出:
wrapper(id=A) is working
wrapper(id=B2) is working
wrapper(id=B1) is working
wrapper(id=B4) is working
wrapper(id=B3) is working
wrapper(id=B5) is working
wrapper(id=C) is working
由于B1-B10是并行的所以正好仅有3个wrapper成功在多线程环境中是比较难遇到的。
*/
}
}

View File

@@ -0,0 +1,75 @@
package v15.cases;
import com.jd.platform.async.executor.Async;
import com.jd.platform.async.wrapper.WorkerWrapper;
import com.jd.platform.async.wrapper.WorkerWrapperBuilder;
import com.jd.platform.async.wrapper.strategy.depend.DependenceAction;
import com.jd.platform.async.wrapper.strategy.depend.DependenceStrategy;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 示例设置一组必须完成的wrapper不推荐使用
*
* @author create by TcSnZh on 2021/5/9-上午1:06
*/
class Case5 {
private static WorkerWrapperBuilder<?, ?> builder(String id) {
return WorkerWrapper.<String, String>builder()
.id(id)
.worker((param, allWrappers) -> {
System.out.println("wrapper(id=" + id + ") is working");
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
});
}
@Deprecated
public static void main(String[] args) throws ExecutionException, InterruptedException {
WorkerWrapper<?, ?> a1 = builder("A1").build();
WorkerWrapper<?, ?> a2 = builder("A2").build();
WorkerWrapper<?, ?> a3 = builder("A3").build();
WorkerWrapper<?, ?> a4 = builder("A4").build();
WorkerWrapper<?, ?> a5 = builder("A5").build();
WorkerWrapper<?, ?> a6 = builder("A6").build();
WorkerWrapper<?, ?> a7 = builder("A7").build();
WorkerWrapper<?, ?> a8 = builder("A8").build();
WorkerWrapper<?, ?> a9 = builder("A9").build();
WorkerWrapper<?, ?> a10 = builder("A10").build();
builder("B")
.setDepend()
// 必须a3、a4成功才能执行
.mustRequireWrapper(a3, a4)
// 如果a3、a4没有成功则休息
.strategy((dependWrappers, thisWrapper, fromWrapper) -> DependenceAction.TAKE_REST.emptyProperty())
.wrapper(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)
.end()
.build();
WorkerWrapper<?, ?> start = builder("start").nextOf(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10).build();
ExecutorService pool = Executors.newFixedThreadPool(2);
try {
Async.work(1000, pool, start).awaitFinish();
} finally {
pool.shutdown();
}
/* 输出:
wrapper(id=A1) is working
wrapper(id=A2) is working
wrapper(id=A4) is working
wrapper(id=A3) is working
wrapper(id=A5) is working
wrapper(id=B) is working
wrapper(id=A6) is working
我们可以看到A3、A4执行后B也执行了之后的wrapper被跳过了
这里之所以a5、a6还在执行只是因为他两正好在WORKING所以没发现后面的B已经可以跳过了
*/
}
}

View File

@@ -0,0 +1,59 @@
package v15.cases;
import com.jd.platform.async.callback.ICallback;
import com.jd.platform.async.executor.Async;
import com.jd.platform.async.worker.ResultState;
import com.jd.platform.async.wrapper.WorkerWrapper;
import com.jd.platform.async.wrapper.WorkerWrapperBuilder;
import com.jd.platform.async.wrapper.strategy.depend.DependenceAction;
import java.util.concurrent.ExecutionException;
/**
* 示例:自定义依赖策略--对单个wrapper设置“上克下”策略--简单使用与示例
*
* @author create by TcSnZh on 2021/5/9-上午1:42
*/
class Case6 {
private static WorkerWrapperBuilder<?, ?> builder(String id) {
return WorkerWrapper.<String, String>builder()
.id(id)
.worker((param, allWrappers) -> {
System.out.println("wrapper(id=" + id + ") is working");
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
});
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
//noinspection unchecked
WorkerWrapper<?, ?> b = builder("B")
// 这里设置了不论a怎么样b都会快速失败。但是a设置的对wrapper的特殊策略把它覆盖了。
.depends((dependWrappers, thisWrapper, fromWrapper) ->
DependenceAction.FAST_FAIL
.fastFailException(ResultState.EXCEPTION, new RuntimeException("b 必定失败除非有上游wrapper救他"))
)
.callback(ICallback.PRINT_EXCEPTION_STACK_TRACE)
.build();
WorkerWrapper<?, ?> a = builder("A")
.setNext()
// a将会使b直接开始工作
// 若是去掉这行代码则b会失败
.specialToNextWrapper(fromWrapper -> DependenceAction.START_WORK.emptyProperty(), b)
.wrapper(b)
.end().build();
Async.work(1000, a).awaitFinish();
System.out.println(a.getWorkResult());
System.out.println(b.getWorkResult());
/* 输出:
wrapper(id=A) is working
wrapper(id=B) is working
WorkResult{result=null, resultState=SUCCESS, ex=null}
WorkResult{result=null, resultState=SUCCESS, ex=null}
*/
}
}

View File

@@ -0,0 +1,61 @@
package v15.cases;
import com.jd.platform.async.executor.Async;
import com.jd.platform.async.worker.ResultState;
import com.jd.platform.async.wrapper.WorkerWrapper;
import com.jd.platform.async.wrapper.WorkerWrapperBuilder;
import com.jd.platform.async.wrapper.strategy.depend.DependenceAction;
import com.jd.platform.async.wrapper.strategy.depend.DependenceStrategy;
import com.jd.platform.async.wrapper.strategy.skip.SkipStrategy;
import java.util.concurrent.ExecutionException;
/**
* @author create by TcSnZh on 2021/5/9-下午4:12
*/
class Case7 {
private static WorkerWrapperBuilder<?, ?> builder(String id) {
return builder(id, -1L);
}
private static WorkerWrapperBuilder<?, ?> builder(String id, long sleepTime) {
return WorkerWrapper.<String, String>builder()
.id(id)
.worker((param, allWrappers) -> {
System.out.println("wrapper(id=" + id + ") is working");
if (sleepTime > 0) {
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return null;
});
}
/**
* A ==> B(10ms) ==> C ==> D (D可在E、C任意一个完成后执行)
* . \====> E(5ms) ====/
*/
public static void main(String[] args) throws ExecutionException, InterruptedException {
WorkerWrapper<?, ?> d = builder("D").depends(DependenceStrategy.ALL_DEPENDENCIES_ANY_SUCCESS).build();
WorkerWrapper<?, ?> a = builder("A")
.nextOf(builder("B", 10)
.nextOf(builder("C")
.nextOf(d)
// 这里我们没有设置C的跳过策略因为默认使用CHECK_ONE_LEVEL可将下行代码注释去掉则C会执行
// .setSkipStrategy(SkipStrategy.NOT_SKIP)
.build())
.build(),
builder("E", 5).nextOf(d).build()
).build();
Async.work(1000, a).awaitFinish();
/* 输出:
wrapper(id=A) is working
wrapper(id=E) is working
wrapper(id=B) is working
wrapper(id=D) is working
*/
}
}

View File

@@ -0,0 +1,74 @@
package v15.cases;
import com.jd.platform.async.callback.ICallback;
import com.jd.platform.async.executor.Async;
import com.jd.platform.async.worker.WorkResult;
import com.jd.platform.async.wrapper.WorkerWrapper;
import com.jd.platform.async.wrapper.WorkerWrapperBuilder;
import com.jd.platform.async.wrapper.strategy.depend.DependenceStrategy;
import java.util.concurrent.ExecutionException;
/**
* @author create by TcSnZh on 2021/5/9-下午4:34
*/
class Case8 {
private static WorkerWrapperBuilder<?, ?> builder(String id) {
return builder(id, -1L);
}
private static WorkerWrapperBuilder<?, ?> builder(String id, long sleepTime) {
return WorkerWrapper.<String, String>builder()
.id(id)
.worker((param, allWrappers) -> {
System.out.println("\twrapper(id=" + id + ") is working");
if (sleepTime > 0) {
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return null;
})
.callback((new ICallback<String, String>() {
@Override
public void begin() {
System.out.println("wrapper(id=" + id + ") has begin . ");
}
@Override
public void result(boolean success, String param, WorkResult<String> workResult) {
System.out.println("\t\twrapper(id=" + id + ") callback "
+ (success ? "success " : "fail ")
+ ", workResult is " + workResult);
}
}));
}
/**
* A ==> B(10ms) ==> C(20ms)
*/
public static void main(String[] args) throws ExecutionException, InterruptedException {
WorkerWrapper<?, ?> a = builder("A")
.nextOf(builder("B", 10)
.nextOf(builder("C", 20).build())
.build())
.build();
Async.work(20, a).awaitFinish();
/* 输出:
wrapper(id=A) has begin .
wrapper(id=A) is working
wrapper(id=A) callback success , workResult is WorkResult{result=null, resultState=SUCCESS, ex=null}
wrapper(id=B) has begin .
wrapper(id=B) is working
wrapper(id=B) callback success , workResult is WorkResult{result=null, resultState=TIMEOUT, ex=null}
wrapper(id=C) has begin .
wrapper(id=C) callback fail , workResult is WorkResult{result=null, resultState=TIMEOUT, ex=null}
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
...
以下异常信息省略
*/
}
}

View File

@@ -0,0 +1,65 @@
package v15.cases;
import com.jd.platform.async.callback.DefaultCallback;
import com.jd.platform.async.executor.Async;
import com.jd.platform.async.openutil.collection.CommonDirectedGraph;
import com.jd.platform.async.openutil.collection.DirectedGraph;
import com.jd.platform.async.wrapper.QuickBuildWorkerWrapper;
import com.jd.platform.async.wrapper.WorkerWrapper;
import com.jd.platform.async.wrapper.strategy.WrapperStrategy;
import java.util.concurrent.*;
/**
* 快速构造示例。
*
* @author create by TcSnZh on 2021/5/17-下午5:23
*/
class Case9 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
DirectedGraph<WorkerWrapper<?, ?>, Object> graph = DirectedGraph.synchronizedDigraph(new CommonDirectedGraph<>());
QuickBuildWorkerWrapper<Object, Object> w1 = new QuickBuildWorkerWrapper<>("id1",
null,
(object, allWrappers) -> {
System.out.println("I am IWorker 1");
return null;
},
new DefaultCallback<>(),
false,
true,
100,
TimeUnit.MILLISECONDS,
new WrapperStrategy.DefaultWrapperStrategy(),
graph
);
QuickBuildWorkerWrapper<Object, Object> w2 = new QuickBuildWorkerWrapper<>("id2",
null,
(object, allWrappers) -> {
System.out.println("I am IWorker 2");
return null;
},
new DefaultCallback<>(),
false,
true,
100,
TimeUnit.MILLISECONDS,
new WrapperStrategy.DefaultWrapperStrategy(),
graph
);
graph.addNode(w1, w2);
graph.putRelation(w1, new Object(), w2);
// System.out.println(graph);
Async.work(200, w1).awaitFinish();
System.out.println(" Begin work end .\n w1 : " + w1 + "\n w2 : " + w2 + "\n");
/* 输出:
I am IWorker 1
I am IWorker 2
Begin work end .
w1 : 省略
w2 : 省略
*/
}
}

View File

@@ -1,14 +1,14 @@
package v15.dependnew;
package v15.wrappertest;
import com.jd.platform.async.callback.IWorker;
import com.jd.platform.async.executor.Async;
import com.jd.platform.async.executor.timer.SystemClock;
import com.jd.platform.async.worker.ResultState;
import com.jd.platform.async.wrapper.actionstrategy.DependenceAction;
import com.jd.platform.async.wrapper.actionstrategy.DependenceStrategy;
import com.jd.platform.async.wrapper.strategy.depend.DependenceAction;
import com.jd.platform.async.wrapper.strategy.depend.DependenceStrategy;
import com.jd.platform.async.wrapper.WorkerWrapper;
import com.jd.platform.async.wrapper.WorkerWrapperBuilder;
import com.jd.platform.async.wrapper.skipstrategy.SkipStrategy;
import com.jd.platform.async.wrapper.strategy.skip.SkipStrategy;
import java.io.PrintStream;
import java.util.*;
@@ -136,7 +136,7 @@ class Test {
}
/**
* 测试旧版本(v1.4及以前)中可能会引发线程耗尽bug的情况
* 测试旧版本(v1.4)中可能会引发线程耗尽bug的情况
* <p>
* A(5ms)--B1(10ms) ---|--> C1(5ms)
* . \ | (B1B2全部完成可执行C1C2)
@@ -195,10 +195,10 @@ class Test {
// B4B5总任务超时
.nextOf(testBuilder("B4", 250).build())
.nextOf(testBuilder("B5", 250)
.setTimeOut().enableTimeOut(true).setTime(300, TimeUnit.MILLISECONDS).allowInterrupt(false).end()
.setTimeOut().enableTimeOut(true).setTime(300, TimeUnit.MILLISECONDS).end()
.build())
// 测试打断B6线程
.nextOf(testBuilder("B6", 250).timeout(true, 150, TimeUnit.MILLISECONDS, true).build())
.nextOf(testBuilder("B6", 250).timeout(true, 150, TimeUnit.MILLISECONDS).allowInterrupt(true).build())
.build();
long t1 = SystemClock.now();
boolean success = Async.beginWork(200, pool, a);

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>asyncTool</artifactId>
<groupId>com.jd.platform</groupId>
<version>1.5.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>asyncTool-openutil</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
</project>

View File

@@ -0,0 +1,109 @@
package com.jd.platform.async.openutil;
import java.util.Comparator;
/**
* 两个int值包装类。重写了{@link #hashCode()}与{@link #equals(Object)}
*
* @author create by TcSnZh on 2021/5/16-上午1:50
*/
public final class BiInt {
// properties
private final int m;
private final int n;
public static final Comparator<BiInt> cmp_m_asc = Comparator.comparingInt(BiInt::getM);
public static final Comparator<BiInt> cmp_n_asc = Comparator.comparingInt(BiInt::getN);
public static final Comparator<BiInt> cmp_m_desc = cmp_m_asc.reversed();
public static final Comparator<BiInt> cmp_n_desc = cmp_n_asc.reversed();
public static final Comparator<BiInt> cmp_m_asc_n_asc =
cmp_m_asc.thenComparing(cmp_n_asc);
public static final Comparator<BiInt> cmp_m_asc_n_desc =
cmp_m_asc.thenComparing(cmp_n_desc);
public static final Comparator<BiInt> cmp_m_desc_n_asc =
cmp_m_desc.thenComparing(cmp_n_asc);
public static final Comparator<BiInt> cmp_m_desc_n_desc =
cmp_m_desc.thenComparing(cmp_n_desc);
public static final Comparator<BiInt> cmp_n_asc_m_asc =
cmp_n_asc.thenComparing(cmp_m_asc);
public static final Comparator<BiInt> cmp_n_asc_m_desc =
cmp_n_asc.thenComparing(cmp_m_desc);
public static final Comparator<BiInt> cmp_n_desc_m_asc =
cmp_n_desc.thenComparing(cmp_m_asc);
public static final Comparator<BiInt> cmp_n_desc_m_desc =
cmp_n_desc.thenComparing(cmp_m_desc);
/**
* private constructor , please use {@link #of(int, int)} to build Idx object.
*/
private BiInt(int m, int n) {
this.m = m;
this.n = n;
}
// getter
public int getM() {
return m;
}
public int getN() {
return n;
}
// hashcode and equals
@Override
public int hashCode() {
return m ^ n;
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (!(o instanceof BiInt))
return false;
BiInt idx = (BiInt) o;
return m == idx.m && n == idx.n;
}
// toString
@Override
public String toString() {
return "(" + m + ',' + n + ')';
}
// ========== static ==========
// 工厂方法
public static BiInt of(int m, int n) {
if (m == Integer.MIN_VALUE && n == Integer.MAX_VALUE) {
return MIN_TO_MAX;
}
if (m >= 0 && m < CACHE_RANGE_M && n >= 0 && n < CACHE_RANGE_M) {
return cache[m * CACHE_RANGE_M + n];
}
return new BiInt(m, n);
}
// 缓存区间
private static final BiInt MIN_TO_MAX = new BiInt(Integer.MIN_VALUE, Integer.MAX_VALUE);
private static final BiInt[] cache; // m from 0 to 31 , n from 0 to 31 , total 1023 .
private static final int CACHE_RANGE_M = 32; // 0 to 31
private static final int CACHE_RANGE_N = 32; // 0 to 31
static {
cache = new BiInt[CACHE_RANGE_M * CACHE_RANGE_N];
for (int i = 0; i < CACHE_RANGE_M; i++) {
for (int j = 0; j < CACHE_RANGE_N; j++) {
cache[i * CACHE_RANGE_M + j] = new BiInt(i, j);
}
}
}
}

View File

@@ -0,0 +1,74 @@
package com.jd.platform.async.openutil.collection;
import com.jd.platform.async.openutil.BiInt;
import java.util.Iterator;
/**
* @author create by TcSnZh on 2021/5/14-下午9:51
*/
public abstract class AbstractArray2D<E> implements Array2D<E> {
/**
* 用于代替null
*/
protected static final Object NULL = new Object() {
@Override
public String toString() {
return "null";
}
@Override
public int hashCode() {
return 0;
}
@SuppressWarnings("EqualsDoesntCheckParameterClass")
@Override
public boolean equals(Object obj) {
//noinspection ConstantConditions
return obj == null || obj == NULL || obj.equals(null);
}
};
@Override
public String toString() {
StringBuilder sb = new StringBuilder(64).append(this.getClass().getSimpleName()).append('{');
Iterator<Point<E>> it = iterator();
if (it.hasNext()) {
while (true) {
Point<E> point = it.next();
sb.append('{').append(point.getIdx()).append(':').append(point.getElement()).append('}');
if (!it.hasNext()) {
break;
}
sb.append(", ");
}
}
return sb.append('}').toString();
}
public static class PointImpl<E> implements Point<E> {
private final BiInt idx;
private final E element;
public PointImpl(BiInt idx, E element) {
this.idx = idx;
this.element = element;
}
@Override
public BiInt getIdx() {
return idx;
}
@Override
public E getElement() {
return element;
}
@Override
public String toString() {
return "{" + idx + ":" + element + "}";
}
}
}

View File

@@ -0,0 +1,88 @@
package com.jd.platform.async.openutil.collection;
import java.util.AbstractSet;
import java.util.Iterator;
import java.util.Objects;
import java.util.Set;
/**
* 抽象有向图
*
* @author create by TcSnZh on 2021/5/13-上午11:37
*/
public abstract class AbstractDirectedGraph<N, R> implements DirectedGraph<N, R> {
@Override
public String toString() {
Set<N> nv = nodesView();
Set<? extends Entry<N, R>> rSet = getRelations();
StringBuilder sb = new StringBuilder(nv.size() * 10 + rSet.size() * 20)
.append(this.getClass().getSimpleName()).append("{nodes=[");
Iterator<N> nit = nodesView().iterator();
if (nit.hasNext()) {
for (; ; ) {
sb.append(nit.next());
if (!nit.hasNext()) {
break;
}
sb.append(", ");
}
}
sb.append("], relations=[");
Iterator<? extends Entry<N, R>> eit = rSet.iterator();
if (eit.hasNext()) {
for (; ; ) {
sb.append(eit.next());
if (!eit.hasNext()) {
break;
}
sb.append(", ");
}
}
return sb.append("]}").toString();
}
public abstract class AbstractNodesView extends AbstractSet<N> {
@Override
public boolean add(N n) {
return AbstractDirectedGraph.this.addNode(n);
}
@Override
public boolean remove(Object o) {
N o1;
//noinspection unchecked
if (!AbstractDirectedGraph.this.containsNode(o1 = (N) o)) {
return false;
}
AbstractDirectedGraph.this.removeNode(o1);
return true;
}
}
public static abstract class AbstractEntry<N, R> implements Entry<N, R> {
@Override
public int hashCode() {
return this.getFrom().hashCode() ^ this.getTo().hashCode() ^ this.getRelation().hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof Graph.Entry)) {
return false;
}
Entry obj1 = (Entry) obj;
return Objects.equals(this.getFrom(), obj1.getFrom())
&& Objects.equals(this.getTo(), obj1.getTo())
&& Objects.equals(this.getRelation(), obj1.getRelation());
}
@Override
public String toString() {
return "{from=" + getFrom() + ", relation=" + getRelation() + ", to=" + getTo() + "]";
}
}
}

View File

@@ -0,0 +1,22 @@
package com.jd.platform.async.openutil.collection;
/**
* @author create by TcSnZh on 2021/5/14-上午2:33
*/
public abstract class AbstractStoreArk<E> implements StoreArk<E> {
@Override
public boolean isEmpty() {
return size() <= 0;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder(size() * 10).append(this.getClass().getSimpleName()).append("{");
if (!isEmpty()) {
stream().forEach(entry -> sb.append(entry.getKey()).append(":").append(entry.getValue()).append(", "));
sb.delete(sb.length() - 2, sb.length());
}
return sb.append("}").toString();
}
}

View File

@@ -0,0 +1,169 @@
package com.jd.platform.async.openutil.collection;
import com.jd.platform.async.openutil.BiInt;
import java.util.*;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
/**
* 二维数组
*
* @author create by TcSnZh on 2021/5/14-下午9:50
*/
@SuppressWarnings("unused")
public interface Array2D<E> extends Iterable<Array2D.Point<E>> {
/**
* 有多少行
*/
int lineLength();
/**
* 有多少列
*/
int columnLength();
/**
* 添加元素到指定位置
*
* @param line 行
* @param column 列
* @param element 元素
* @return 如果之前添加过元素,将返回替换掉的之前的元素
* @throws IndexOutOfBoundsException 行列超出范围
*/
E add(int line, int column, E element);
/**
* 如果不存在的话则添加元素
* <p>
* {@link #add(int, int, Object)}
*
* @return 不存在且成功添加返回true。
*/
default boolean addIfAbsent(int line, int column, E element) {
if (get(line, column) != null) {
return false;
}
add(line, column, element);
return true;
}
/**
* 删除元素
*
* @param line 行
* @param column 列
* @return 返回移出的元素
* @throws IndexOutOfBoundsException 行列超出返回
* @throws IllegalArgumentException 如果原本不存在元素
*/
E remove(int line, int column);
/**
* 存在则移除不存在则返回null
*
* @param line 行
* @param column 列
* @return 如果不存在返回null。存在则返回被移出的元素。
* @throws IndexOutOfBoundsException 行列超出范围
*/
default E removeIfAbsent(int line, int column) {
if (get(line, column) == null) {
return null;
}
return remove(line, column);
}
/**
* 获取元素
*
* @param line 行
* @param column 列
* @return 如果存在返回该元素。不存在则返回null。
* @throws IndexOutOfBoundsException 行列超出范围
*/
E get(int line, int column);
/**
* 是否包含元素
*
* @param element 元素
* @return 有这个元素就返回true。
*/
boolean containsElement(E element);
/**
* 获取整行的元素
*
* @param line 行号
* @return 返回key为列号value为元素的Map
* @throws IndexOutOfBoundsException 行号超出范围
*/
Map<Integer, E> fullLine(int line);
/**
* 获取整列的元素
*
* @param column 列号
* @return 返回key为行号value为元素的Map
* @throws IndexOutOfBoundsException 列号超出范围
*/
Map<Integer, E> fullColumn(int column);
/**
* 迭代器
*
* @param foreachOrder 遍历顺序
* @return 如果本容器不允许null值存在只需返回存在的元素的键即可。如果允许null值存在仅需返回包括人工放入的null值的键即可。
*/
Iterator<? extends Point<E>> iterator(Comparator<BiInt> foreachOrder);
@Override
default Iterator<Point<E>> iterator() {
//noinspection unchecked
return (Iterator) iterator(BiInt.cmp_m_asc_n_asc);
}
/**
* 流
*/
default Stream<? extends Point<E>> stream() {
return StreamSupport.stream(spliterator(), false);
}
default Stream<? extends Point<E>> parallelStream() {
return StreamSupport.stream(spliterator(), true);
}
default Spliterator<Point<E>> spliterator(Comparator<BiInt> foreachOrder) {
return Spliterators.spliteratorUnknownSize(iterator(foreachOrder), 0);
}
default Stream<? extends Point<E>> stream(Comparator<BiInt> foreachOrder) {
return StreamSupport.stream(spliterator(foreachOrder), false);
}
default Stream<? extends Point<E>> parallelStream(Comparator<BiInt> foreachOrder) {
return StreamSupport.stream(spliterator(foreachOrder), true);
}
/**
* 端点
*
* @param <E> 元素泛型
*/
interface Point<E> {
BiInt getIdx();
default int getLine() {
return getIdx().getM();
}
default int getColumn() {
return getIdx().getN();
}
E getElement();
}
}

View File

@@ -0,0 +1,60 @@
package com.jd.platform.async.openutil.collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.function.Supplier;
/**
* 一个缓存元素位置的储存柜。
*
* @author create by TcSnZh on 2021/5/14-上午2:37
*/
public class CachedStoreArk<E> extends AbstractStoreArk<E> {
private final StoreArk<E> inner;
private final Map<E, Integer> cacheMap = new HashMap<>();
public CachedStoreArk() {
this(CommonStoreArk::new);
}
private CachedStoreArk(Supplier<StoreArk<E>> sup) {
this.inner = sup.get();
}
@Override
public int store(E element) {
int id = inner.store(element);
cacheMap.put(element, id);
return id;
}
@Override
public E peek(int id) {
return inner.peek(id);
}
@Override
public E takeOut(int id) {
E e = inner.takeOut(id);
cacheMap.remove(e);
return e;
}
@Override
public int size() {
return inner.size();
}
@Override
public Iterator<Map.Entry<Integer, E>> iterator() {
return inner.iterator();
}
@Override
public int findId(E element) {
Integer idNullable = cacheMap.get(element);
return idNullable == null ? -1 : idNullable;
}
}

View File

@@ -0,0 +1,145 @@
package com.jd.platform.async.openutil.collection;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* 线程不安全的有向图。
* <p/>
* 不允许放入null。
*
* @author create by TcSnZh on 2021/5/14-上午2:22
*/
public class CommonDirectedGraph<N, R> extends AbstractDirectedGraph<N, R> {
// ========== properties ==========
private final StoreArk<N> nodes = new CachedStoreArk<>();
private final Array2D<R> arr = new SparseArray2D<>();
// ========== methods ==========
@Override
public boolean addNode(N node) {
if (containsNode(Objects.requireNonNull(node))) {
return false;
}
nodes.store(node);
return true;
}
@Override
public boolean containsNode(N node) {
return node != null && findNodeId(node, false) >= 0;
}
@Override
public Set<? extends Entry<N, R>> removeNode(N node) {
int id = findNodeId(Objects.requireNonNull(node), true);
LinkedHashSet<Entry<N, R>> res = new LinkedHashSet<>();
// 查找node为from的键
arr.fullLine(id).forEach((toNodeId, relation) -> {
res.add(new OuterEntry<>(node, nodes.peek(toNodeId), relation));
arr.remove(id, toNodeId);
});
// 查找node为to的键
arr.fullColumn(id).forEach((fromNodeId, relation) -> {
// 在上一次遍历中fromNodeId为id
if (fromNodeId == id) {
return;
}
res.add(new OuterEntry<>(nodes.peek(fromNodeId), node, relation));
arr.remove(fromNodeId, id);
});
nodes.takeOut(id);
return res;
}
@Override
public R putRelation(N fromNode, R relation, N toNode) {
return arr.add(
findNodeId(Objects.requireNonNull(fromNode), true),
findNodeId(Objects.requireNonNull(toNode), true),
Objects.requireNonNull(relation)
);
}
@Override
public Set<? extends Entry<N, R>> getRelationFrom(N from) {
int id = findNodeId(Objects.requireNonNull(from), true);
LinkedHashSet<Entry<N, R>> res = new LinkedHashSet<>();
// 查找node为from的键
arr.fullLine(id).forEach((toNodeId, relation) -> res.add(new OuterEntry<>(from, nodes.peek(toNodeId), relation)));
return res;
}
@Override
public Set<? extends Entry<N, R>> getRelationTo(N to) {
int id = findNodeId(Objects.requireNonNull(to), true);
LinkedHashSet<Entry<N, R>> res = new LinkedHashSet<>();
// 查找node为to的键
arr.fullColumn(id).forEach((fromNodeId, relation) ->
res.add(new OuterEntry<>(nodes.peek(fromNodeId), to, relation)));
return res;
}
@Override
public Set<N> nodesView() {
return new AbstractNodesView() {
@Override
public Iterator<N> iterator() {
return nodes.stream().map(Map.Entry::getValue).iterator();
}
@Override
public int size() {
return nodes.size();
}
};
}
@Override
public Set<? extends Entry<N, R>> getRelations() {
return arr.stream().map((Function<Array2D.Point<R>, Entry<N, R>>) rPoint -> new OuterEntry<>(
nodes.peek(rPoint.getLine()),
nodes.peek(rPoint.getColumn()),
rPoint.getElement()
)).collect(Collectors.toSet());
}
private int findNodeId(N node, boolean mustExistElseThrowEx) {
int id = nodes.findId(Objects.requireNonNull(node));
if (mustExistElseThrowEx && id < 0) {
throw new IllegalArgumentException("No node exists : " + node);
}
return id;
}
private static class OuterEntry<N, R> extends AbstractEntry<N, R> {
private final N from;
private final N to;
private final R relation;
public OuterEntry(N from, N to, R relation) {
this.from = from;
this.to = to;
this.relation = relation;
}
@Override
public N getFrom() {
return from;
}
@Override
public N getTo() {
return to;
}
@Override
public R getRelation() {
return relation;
}
}
}

View File

@@ -0,0 +1,159 @@
package com.jd.platform.async.openutil.collection;
import java.util.*;
/**
* 自动扩容的id储物柜线程不安全。
*
* @author create by TcSnZh on 2021/5/13-下午1:24
*/
public class CommonStoreArk<E> extends AbstractStoreArk<E> {
private Object[] elements;
/**
* 已经分配的下标数
*/
private int allocSize = 0;
/**
* 保存着最小空元素的队列
*/
private final Queue<Integer> emptyPoints = new PriorityQueue<>(Integer::compareTo);
public CommonStoreArk(int initialCapacity) {
elements = new Object[initialCapacity];
}
public CommonStoreArk() {
this(10);
}
@Override
public int store(E element) {
int id;
elements[id = pollId()] = element;
return id;
}
@Override
public E peek(int id) {
if (id < 0) {
throw new IllegalArgumentException("id " + id + " can't be negative");
}
if (id >= elements.length) {
return null;
}
//noinspection unchecked
return (E) elements[id];
}
@Override
public E takeOut(int id) {
if (id < 0) {
throw new IllegalArgumentException("id " + id + " can't be negative");
}
if (id >= elements.length) {
return null;
}
//noinspection unchecked
E out = (E) elements[id];
elements[id] = null;
if (id == allocSize - 1) {
allocSize--;
} else {
emptyPoints.add(id);
}
return out;
}
@Override
public int size() {
return allocSize - emptyPoints.size();
}
@Override
public Iterator<Map.Entry<Integer, E>> iterator() {
return new Iterator<Map.Entry<Integer, E>>() {
private final Map.Entry<Integer, E>[] items;
private int idx = 0;
{
//noinspection unchecked
items = new Map.Entry[size()];
int itemsIdx = 0;
Iterator<Integer> emptyPointItr = emptyPoints.iterator();
for (int i = 0; i < allocSize; i++) {
Object element = elements[i];
if (element == null) {
continue;
}
final int _i = i;
//noinspection unchecked
items[itemsIdx++] = new Map.Entry<Integer, E>() {
private final int k = _i;
private E v = (E) element;
@Override
public Integer getKey() {
return k;
}
@Override
public E getValue() {
return v;
}
@Override
public E setValue(E value) {
E _v = this.v;
this.v = value;
return _v;
}
@Override
public String toString() {
return "{" + k + ':' + v + '}';
}
};
}
}
@Override
public boolean hasNext() {
return idx < items.length;
}
@Override
public Map.Entry<Integer, E> next() {
return items[idx++];
}
};
}
@Override
public int findId(E element) {
int i = 0;
for (Object o : elements) {
if (Objects.equals(o, element)) {
return i;
}
i++;
}
return -1;
}
private int pollId() {
if (!emptyPoints.isEmpty()) {
return emptyPoints.poll();
}
int id = allocSize++;
int length = elements.length;
if (id >= length) {
// 扩容
elements = Arrays.copyOf(elements, Math.max(length + 1, length + (length >> 1)));
}
return id;
}
}

View File

@@ -0,0 +1,182 @@
package com.jd.platform.async.openutil.collection;
import java.util.*;
/**
* @author create by TcSnZh on 2021/5/16-下午11:27
*/
public interface DirectedGraph<N, R> extends Graph<N, R> {
@Override
default boolean isDirected() {
return true;
}
static <N, R> DirectedGraph<N, R> readOnlyDigraph(DirectedGraph<N, R> source) {
return new ReadOnlyDirectedGraph<>(source);
}
static <N, R> DirectedGraph<N, R> synchronizedDigraph(DirectedGraph<N, R> source) {
return synchronizedDigraph(source, new Object());
}
static <N, R> DirectedGraph<N, R> synchronizedDigraph(DirectedGraph<N, R> source, Object mutex) {
return new SyncDirectedGraph<>(source, mutex);
}
class ReadOnlyDirectedGraph<N, R> extends AbstractDirectedGraph<N, R> {
private final DirectedGraph<N, R> source;
public ReadOnlyDirectedGraph(DirectedGraph<N, R> source) {
this.source = source;
}
private static UnsupportedOperationException readOnlyGraph() {
return new UnsupportedOperationException("readOnly graph");
}
@Override
public boolean addNode(N node) {
throw readOnlyGraph();
}
@Override
public boolean containsNode(N node) {
return source.containsNode(node);
}
@Override
public Set<? extends Entry<N, R>> removeNode(N node) {
throw readOnlyGraph();
}
@Override
public R putRelation(N fromNode, R relation, N toNode) {
throw readOnlyGraph();
}
@Override
public Set<? extends Entry<N, R>> getRelationFrom(N from) {
return source.getRelationFrom(from);
}
@Override
public Set<? extends Entry<N, R>> getRelationTo(N to) {
return source.getRelationTo(to);
}
@Override
public Set<N> nodesView() {
return new AbstractSet<N>() {
private final Set<N> nodesViewSource = source.nodesView();
@Override
public Iterator<N> iterator() {
return new Iterator<N>() {
private final Iterator<N> iteratorSource = nodesViewSource.iterator();
@Override
public boolean hasNext() {
return iteratorSource.hasNext();
}
@Override
public N next() {
return iteratorSource.next();
}
@Override
public void remove() {
throw readOnlyGraph();
}
};
}
@Override
public int size() {
return nodesViewSource.size();
}
@Override
public boolean add(N n) {
throw readOnlyGraph();
}
@Override
public boolean remove(Object o) {
throw readOnlyGraph();
}
};
}
@Override
public Set<? extends Entry<N, R>> getRelations() {
return source.getRelations();
}
}
class SyncDirectedGraph<N, R> extends AbstractDirectedGraph<N, R> {
private final DirectedGraph<N, R> source;
private final Object mutex;
public SyncDirectedGraph(DirectedGraph<N, R> source, Object mutex) {
this.source = source;
this.mutex = mutex;
}
@Override
public boolean addNode(N node) {
synchronized (mutex) {
return source.addNode(node);
}
}
@Override
public boolean containsNode(N node) {
synchronized (mutex) {
return source.containsNode(node);
}
}
@Override
public Set<? extends Entry<N, R>> removeNode(N node) {
synchronized (mutex) {
return source.removeNode(node);
}
}
@Override
public R putRelation(N fromNode, R relation, N toNode) {
synchronized (mutex) {
return source.putRelation(fromNode, relation, toNode);
}
}
@Override
public Set<? extends Entry<N, R>> getRelationFrom(N from) {
synchronized (mutex) {
return source.getRelationFrom(from);
}
}
@Override
public Set<? extends Entry<N, R>> getRelationTo(N to) {
synchronized (mutex) {
return source.getRelationTo(to);
}
}
@Override
public Set<N> nodesView() {
synchronized (mutex) {
return Collections.synchronizedSet(source.nodesView());
}
}
@Override
public Set<? extends Entry<N, R>> getRelations() {
synchronized (mutex) {
return source.getRelations();
}
}
}
}

View File

@@ -0,0 +1,106 @@
package com.jd.platform.async.openutil.collection;
import java.util.Set;
/**
* 图数据结构
*
* @author create by TcSnZh on 2021/5/13-上午11:37
*/
@SuppressWarnings("unused")
public interface Graph<N, R> {
/**
* 添加节点。
* 如果节点已经存在,则不会添加。
*
* @param node 添加进图的节点
* @return 添加成功返回true如果节点已经存在返回false。
*/
boolean addNode(N node);
/**
* 添加一堆Node任一成功返回true
*/
default boolean addNode(N... nodes) {
boolean success = false;
for (N node : nodes) {
if (addNode(node)) {
success = true;
}
}
return success;
}
/**
* 是否存在节点
*
* @param node 节点。
* @return 存在返回true否则返回false。
*/
boolean containsNode(N node);
/**
* 移除节点。
* 返回与该节点有关系的,被一并移出的键。
*
* @param node 节点
* @return 返回值不会为null。
* @throws IllegalArgumentException 如果两个节点任一不存在本图中,抛出异常。
*/
Set<? extends Entry<N, R>> removeNode(N node);
/**
* 添加关系
* 在无向图中fromNode与toNode参数的位置调换没有影响。
*
* @param fromNode 从这个节点开始
* @param relation 关系
* @param toNode 以那个节点为目标
* @return 如果之前存在关系则会替换之前的关系返回出被替换的之前存在的关系。如果之前没有关系返回null。
* @throws IllegalArgumentException 如果两个节点任一不存在本图中,抛出该异常。
*/
R putRelation(N fromNode, R relation, N toNode);
/**
* 获取“从这个节点开始”的所有关系
*
* @param from 关系开始的节点
* @return 返回 {@link Entry}键。
*/
Set<? extends Entry<N, R>> getRelationFrom(N from);
/**
* 获取“以这个节点为目标”的所有关系
*
* @param to 被关系的节点
* @return 返回 {@link Entry}键。
*/
Set<? extends Entry<N, R>> getRelationTo(N to);
/**
* 返回全部节点视图
*
* @return 视图
*/
Set<N> nodesView();
/**
* 返回全部关系返回的是新Set
*
* @return 与本类无关的Set
*/
Set<? extends Entry<N, R>> getRelations();
/**
* 是否有向
*/
boolean isDirected();
interface Entry<N, R> {
N getFrom();
N getTo();
R getRelation();
}
}

View File

@@ -0,0 +1,230 @@
package com.jd.platform.async.openutil.collection;
import com.jd.platform.async.openutil.BiInt;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* 稀疏二维数组。
* <p/>
* 可以设置是否允许存入null。
*
* @author create by TcSnZh on 2021/5/14-下午9:45
*/
public class SparseArray2D<E> extends AbstractArray2D<E> {
// ========== properties ==========
/**
* 限制长宽默认为Integer.MAX_VALUE。稀疏数组不在乎这些。
*/
private final int maxLineLength;
private final int maxColumnLength;
private final boolean allowNull;
private final Map<BiInt, Object> items = new HashMap<>();
// ========== index cache properties ==========
/**
* 缓存行列索引
*/
private final NavigableMap<Integer, NavigableSet<Integer>> indexOfLine2columns = new TreeMap<>(Integer::compareTo);
private final NavigableMap<Integer, NavigableSet<Integer>> indexOfColumn2lines = new TreeMap<>(Integer::compareTo);
// ========== constructor ==========
public SparseArray2D() {
this(Integer.MAX_VALUE, Integer.MAX_VALUE);
}
public SparseArray2D(boolean allowNull) {
this(Integer.MAX_VALUE, Integer.MAX_VALUE, allowNull);
}
public SparseArray2D(int maxLineCapacity, int maxColumnCapacity) {
this(maxLineCapacity, maxColumnCapacity, false);
}
public SparseArray2D(int maxLineCapacity, int maxColumnCapacity, boolean allowNull) {
this.maxLineLength = maxLineCapacity;
this.maxColumnLength = maxColumnCapacity;
this.allowNull = allowNull;
}
// ========== public methods ==========
@Override
public int lineLength() {
return maxLineLength;
}
@Override
public int columnLength() {
return maxColumnLength;
}
@Override
public E add(int line, int column, E element) {
if (!allowNull && element == null) {
throw new NullPointerException("null is not allowed");
}
Object put = items.put(BiInt.of(checkLine(line), checkColumn(column)), element == null ? NULL : element);
addIndex(line, column);
//noinspection unchecked
return NULL.equals(put) ? null : (E) put;
}
@Override
public E remove(int line, int column) {
BiInt idx = BiInt.of(checkLine(line), checkColumn(column));
Object get = items.get(idx);
if (get == null) {
throw new IllegalArgumentException("There is no element in line " + line + " column " + column);
}
items.remove(idx);
removeIndex(line, column);
//noinspection unchecked
return NULL.equals(get) ? null : (E) get;
}
/**
* 该方法如果返回null则分不清 之前存入了null 还是 没有存入过
* <p>
* {@inheritDoc}
*/
@Override
public E get(int line, int column) {
Object get = items.get(BiInt.of(checkLine(line), checkColumn(column)));
//noinspection unchecked
return NULL.equals(get) ? null : (E) get;
}
@Override
public boolean containsElement(E element) {
if (NULL.equals(element)) {
if (!allowNull) {
return false;
}
return items.values().stream().anyMatch(v -> NULL.equals(element));
}
return items.values().stream().anyMatch(element::equals);
}
@Override
public Map<Integer, E> fullLine(int line) {
return Optional.ofNullable(indexOfLine2columns.get(line))
.map(set -> set.stream()
.collect(Collectors.toMap(column -> column, column -> {
//noinspection unchecked
return (E) items.get(BiInt.of(line, column));
})))
.orElse(Collections.emptyMap());
}
@Override
public Map<Integer, E> fullColumn(int column) {
return Optional.ofNullable(indexOfColumn2lines.get(column))
.map(set -> set.stream()
.collect(Collectors.toMap(line -> line, line -> {
//noinspection unchecked
return (E) items.get(BiInt.of(line, column));
})))
.orElse(Collections.emptyMap());
}
@Override
public Iterator<? extends Point<E>> iterator(Comparator<BiInt> foreachOrder) {
return new Iterator<Point<E>>() {
private final Iterator<Map.Entry<BiInt, Object>> it;
private Point<E> last = null;
private boolean removed = false;
{
it = items.entrySet().stream()
.sorted((o1, o2) -> foreachOrder.compare(o1.getKey(), o2.getKey()))
.iterator();
}
@Override
public boolean hasNext() {
return it.hasNext();
}
@Override
public Point<E> next() {
Map.Entry<BiInt, Object> next = it.next();
removed = false;
Object v = next.getValue();
//noinspection unchecked
return last = new PointImpl<>(next.getKey(), NULL.equals(v) ? null : (E) v);
}
@Override
public void remove() {
if (last == null || removed) {
throw new IllegalStateException(last == null
? "Iterator has not yet been called .next() ."
: "Iterator item already removed : " + last);
}
BiInt idx = last.getIdx();
SparseArray2D.this.remove(idx.getM(), idx.getN());
}
};
}
// ========== private methods ==========
private int checkLine(int line) {
int len = lineLength();
if (line < 0 || line >= len) {
throw new IndexOutOfBoundsException("Line " + line + " out of bound [0," + (len - 1) + "]");
}
return line;
}
private int checkColumn(int column) {
int len = columnLength();
if (column < 0 || column >= len) {
throw new IndexOutOfBoundsException("Column " + column + " out of bound [0," + (len - 1) + "]");
}
return column;
}
private void addIndex(int line, int column) {
indexOfLine2columns.computeIfAbsent(line, line1 -> new TreeSet<>(Integer::compareTo)).add(column);
indexOfColumn2lines.computeIfAbsent(column, column1 -> new TreeSet<>(Integer::compareTo)).add(line);
}
private void removeIndex(int line, int column) {
// remove line index
{
NavigableSet<Integer> columns = indexOfLine2columns.get(line);
if (columns == null || !columns.contains(column)) {
throw new ConcurrentModificationException(
"线程不安全导致索引异常 : lines " + columns + " is null or not contain line " + line);
}
if (columns.size() == 1) {
indexOfLine2columns.remove(line);
} else {
columns.remove(column);
}
}
// remove column index
{
NavigableSet<Integer> lines = indexOfColumn2lines.get(column);
if (lines == null || !lines.contains(line)) {
throw new ConcurrentModificationException(
"线程不安全导致索引异常 : lines " + lines + " is null or not contain column " + column);
}
if (lines.size() == 1) {
indexOfColumn2lines.remove(column);
} else {
lines.remove(column);
}
}
}
}

View File

@@ -0,0 +1,69 @@
package com.jd.platform.async.openutil.collection;
import java.util.Map;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
/**
* id存储柜。
* 每个元素的id是固定的除非取出后重新加入且id是大于等于0且分配到的id必须是未分配的id中最小的。
* <p>
* 类似于我们去游泳馆,里面的存放个人物品的柜子。
* 放进去元素后会分配一个id。然后凭借该id取出元素。
* 不过不同于这些现实中的柜子的是这个存储柜必定会提供最小的id并且必定>0。
* </p>
*
* @author create by TcSnZh on 2021/5/14-上午2:29
*/
public interface StoreArk<E> extends Iterable<Map.Entry<Integer, E>> {
/**
* 存入元素
*
* @param element 元素。
* @return 返回最小的id。从0开始。
*/
int store(E element);
/**
* 查看元素
*
* @param id id;
* @return 返回存在的元素。如果本id未被占用 或 原先存入null返回null。
* @throws IllegalArgumentException id为负数时抛出该异常
*/
E peek(int id);
/**
* 取出元素
*
* @param id id
* @return 返回被取出的元素。如果本id未被占用 或 原先存入null返回null。
* @throws IllegalArgumentException id为负数时抛出该异常
*/
E takeOut(int id);
/**
* 元素个数
*/
int size();
/**
* 是否为空
*/
boolean isEmpty();
/**
* 查找元素的id
*
* @param element 元素
* @return 如果存在返回id。不存在返回-1
*/
int findId(E element);
/**
* 返回流
*/
default Stream<Map.Entry<Integer, E>> stream() {
return StreamSupport.stream(spliterator(), false);
}
}

View File

@@ -0,0 +1,18 @@
package com.jd.platform.async.openutil.timer;
/**
* @author create by TcSnZh on 2021/5/12-下午6:36
*/
public abstract class AbstractWheelTimer implements Timer, AutoCloseable {
public static final int WORKER_STATE_INIT = 0;
public static final int WORKER_STATE_STARTED = 1;
public static final int WORKER_STATE_SHUTDOWN = 2;
public abstract void start();
@SuppressWarnings("RedundantThrows")
@Override
public void close() throws Exception {
stop();
}
}

View File

@@ -0,0 +1,665 @@
package com.jd.platform.async.openutil.timer;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
import java.util.concurrent.atomic.AtomicLong;
/**
* 从netty里抄来的删去了一些功能。
* <p/>
* <b>
* 如果违反开源协议,请联系作者: zh.jobs@foxmail.com
* If violate the open source agreement, please contact the author : zh0u.he@qq.com
* </b>
*
* @author create by TcSnZh on 2021/5/12-下午7:16
*/
public class HashedWheelTimer extends AbstractWheelTimer {
private static final long MILLISECOND_NANOS = TimeUnit.MILLISECONDS.toNanos(1);
private final Worker worker = new Worker();
private final Thread workerThread;
@SuppressWarnings({"unused", "FieldMayBeFinal"})
private final AtomicInteger workerState = new AtomicInteger(WORKER_STATE_INIT); // 0 - init, 1 - started, 2 - shut down
private final long tickDuration;
private final HashedWheelBucket[] wheel;
private final int mask;
private final CountDownLatch startTimeInitialized = new CountDownLatch(1);
private final Queue<HashedWheelTimeout> timeouts = new ConcurrentLinkedDeque<>();
private final Queue<HashedWheelTimeout> cancelledTimeouts = new ConcurrentLinkedDeque<>();
private final AtomicLong pendingTimeouts = new AtomicLong(0);
private final long maxPendingTimeouts;
private volatile long startTime;
/**
* Creates a new timer with the default thread factory
* ({@link Executors#defaultThreadFactory()}), default tick duration, and
* default number of ticks per wheel.
*/
@SuppressWarnings("unused")
public HashedWheelTimer() {
this(Executors.defaultThreadFactory());
}
/**
* Creates a new timer with the default thread factory
* ({@link Executors#defaultThreadFactory()}) and default number of ticks
* per wheel.
*
* @param tickDuration the duration between tick
* @param unit the time unit of the {@code tickDuration}
* @throws NullPointerException if {@code unit} is {@code null}
* @throws IllegalArgumentException if {@code tickDuration} is &lt;= 0
*/
@SuppressWarnings("unused")
public HashedWheelTimer(long tickDuration, TimeUnit unit) {
this(Executors.defaultThreadFactory(), tickDuration, unit);
}
/**
* Creates a new timer with the default thread factory
* ({@link Executors#defaultThreadFactory()}).
*
* @param tickDuration the duration between tick
* @param unit the time unit of the {@code tickDuration}
* @param ticksPerWheel the size of the wheel
* @throws NullPointerException if {@code unit} is {@code null}
* @throws IllegalArgumentException if either of {@code tickDuration} and {@code ticksPerWheel} is &lt;= 0
*/
@SuppressWarnings("unused")
public HashedWheelTimer(long tickDuration, TimeUnit unit, int ticksPerWheel) {
this(Executors.defaultThreadFactory(), tickDuration, unit, ticksPerWheel);
}
/**
* Creates a new timer with the default tick duration and default number of
* ticks per wheel.
*
* @param threadFactory a {@link ThreadFactory} that creates a
* background {@link Thread} which is dedicated to
* {@link TimerTask} execution.
* @throws NullPointerException if {@code threadFactory} is {@code null}
*/
public HashedWheelTimer(ThreadFactory threadFactory) {
this(threadFactory, 100, TimeUnit.MILLISECONDS);
}
/**
* Creates a new timer with the default number of ticks per wheel.
*
* @param threadFactory a {@link ThreadFactory} that creates a
* background {@link Thread} which is dedicated to
* {@link TimerTask} execution.
* @param tickDuration the duration between tick
* @param unit the time unit of the {@code tickDuration}
* @throws NullPointerException if either of {@code threadFactory} and {@code unit} is {@code null}
* @throws IllegalArgumentException if {@code tickDuration} is &lt;= 0
*/
public HashedWheelTimer(
ThreadFactory threadFactory, long tickDuration, TimeUnit unit) {
this(threadFactory, tickDuration, unit, 512);
}
/**
* Creates a new timer.
*
* @param threadFactory a {@link ThreadFactory} that creates a
* background {@link Thread} which is dedicated to
* {@link TimerTask} execution.
* @param tickDuration the duration between tick
* @param unit the time unit of the {@code tickDuration}
* @param ticksPerWheel the size of the wheel
* @throws NullPointerException if either of {@code threadFactory} and {@code unit} is {@code null}
* @throws IllegalArgumentException if either of {@code tickDuration} and {@code ticksPerWheel} is &lt;= 0
*/
public HashedWheelTimer(
ThreadFactory threadFactory,
long tickDuration, TimeUnit unit, int ticksPerWheel) {
this(threadFactory, tickDuration, unit, ticksPerWheel, -1);
}
/**
* Creates a new timer.
*
* @param threadFactory a {@link ThreadFactory} that creates a
* background {@link Thread} which is dedicated to
* {@link TimerTask} execution.
* @param tickDuration the duration between tick
* @param unit the time unit of the {@code tickDuration}
* @param ticksPerWheel the size of the wheel
* @param maxPendingTimeouts The maximum number of pending timeouts after which call to
* {@code newTimeout} will result in
* {@link RejectedExecutionException}
* being thrown. No maximum pending timeouts limit is assumed if
* this value is 0 or negative.
* @throws NullPointerException if either of {@code threadFactory} and {@code unit} is {@code null}
* @throws IllegalArgumentException if either of {@code tickDuration} and {@code ticksPerWheel} is &lt;= 0
*/
public HashedWheelTimer(ThreadFactory threadFactory,
long tickDuration,
TimeUnit unit,
int ticksPerWheel,
long maxPendingTimeouts) {
Objects.requireNonNull(threadFactory, "threadFactory must not null !");
Objects.requireNonNull(threadFactory, "unit must not null !");
if (tickDuration <= 0) {
throw new IllegalArgumentException("tickDuration should > 0 !");
}
if (ticksPerWheel <= 0) {
throw new IllegalArgumentException("ticksPerWheel should > 0 !");
}
wheel = createWheel(ticksPerWheel);
mask = wheel.length - 1;
long duration = unit.toNanos(tickDuration);
// 检查一个周期是否比Long.MAX_VALUE还长
if (duration >= Long.MAX_VALUE / wheel.length) {
throw new IllegalArgumentException(String.format(
"tickDuration: %d (expected: 0 < tickDuration in nanos < %d",
tickDuration, Long.MAX_VALUE / wheel.length));
}
this.tickDuration = Math.max(duration, MILLISECOND_NANOS);
workerThread = threadFactory.newThread(worker);
this.maxPendingTimeouts = maxPendingTimeouts;
}
private static HashedWheelBucket[] createWheel(int ticksPerWheel) {
if (ticksPerWheel <= 0) {
throw new IllegalArgumentException(
"ticksPerWheel must be greater than 0: " + ticksPerWheel);
}
if (ticksPerWheel > 1073741824) {
throw new IllegalArgumentException(
"ticksPerWheel may not be greater than 2^30: " + ticksPerWheel);
}
ticksPerWheel = normalizeTicksPerWheel(ticksPerWheel);
HashedWheelBucket[] wheel = new HashedWheelBucket[ticksPerWheel];
for (int i = 0; i < wheel.length; i++) {
wheel[i] = new HashedWheelBucket();
}
return wheel;
}
private static int normalizeTicksPerWheel(int ticksPerWheel) {
int normalizedTicksPerWheel = 1;
while (normalizedTicksPerWheel < ticksPerWheel) {
normalizedTicksPerWheel <<= 1;
}
return normalizedTicksPerWheel;
}
/**
* 显式启动后台线程。即使您没有调用此方法,后台线程也将根据需要自动启动。
*
* @throws IllegalStateException 如果此计时器已停止{@link #stop()}
*/
@Override
public void start() {
switch (workerState.get()) {
case WORKER_STATE_INIT:
if (workerState.compareAndSet(WORKER_STATE_INIT, WORKER_STATE_STARTED)) {
workerThread.start();
}
break;
case WORKER_STATE_STARTED:
break;
case WORKER_STATE_SHUTDOWN:
throw new IllegalStateException("cannot be started once stopped");
default:
throw new Error("Invalid WorkerState");
}
// Wait until the startTime is initialized by the worker.
while (startTime == 0) {
try {
startTimeInitialized.await();
} catch (InterruptedException ignore) {
// Ignore - it will be ready very soon.
}
}
}
@Override
public Set<Timeout> stop() {
if (Thread.currentThread() == workerThread) {
throw new IllegalStateException(
HashedWheelTimer.class.getSimpleName() +
".stop() cannot be called from " +
TimerTask.class.getSimpleName());
}
if (!workerState.compareAndSet(WORKER_STATE_STARTED, WORKER_STATE_SHUTDOWN)) {
// state is init or shutdown .
return Collections.emptySet();
}
boolean interrupted = false;
while (workerThread.isAlive()) {
workerThread.interrupt();
try {
workerThread.join(100);
} catch (InterruptedException ignored) {
interrupted = true;
}
}
if (interrupted) {
Thread.currentThread().interrupt();
}
return worker.unprocessedTimeouts();
}
@Override
public Timeout newTimeout(TimerTask task, long delay, TimeUnit unit) {
Objects.requireNonNull(task, "task require not null !");
Objects.requireNonNull(unit, "unit require not null !");
long pendingTimeoutsCount = pendingTimeouts.incrementAndGet();
if (maxPendingTimeouts > 0 && pendingTimeoutsCount > maxPendingTimeouts) {
pendingTimeouts.decrementAndGet();
throw new RejectedExecutionException("Number of pending timeouts ("
+ pendingTimeoutsCount + ") is greater than or equal to maximum allowed pending "
+ "timeouts (" + maxPendingTimeouts + ")");
}
start();
// Add the timeout to the timeout queue which will be processed on the next tick.
// During processing all the queued HashedWheelTimeouts will be added to the correct HashedWheelBucket.
long deadline = System.nanoTime() + unit.toNanos(delay) - startTime;
// Guard against overflow.
if (delay > 0 && deadline < 0) {
deadline = Long.MAX_VALUE;
}
HashedWheelTimeout timeout = new HashedWheelTimeout(this, task, deadline);
timeouts.add(timeout);
return timeout;
}
/**
* Returns the number of pending timeouts of this {@link Timer}.
*/
public long pendingTimeouts() {
return pendingTimeouts.get();
}
private final class Worker implements Runnable {
private final Set<Timeout> unprocessedTimeouts = new HashSet<Timeout>();
private long tick;
@Override
public void run() {
// Initialize the startTime.
startTime = System.nanoTime();
if (startTime == 0) {
// We use 0 as an indicator for the uninitialized value here, so make sure it's not 0 when initialized.
startTime = 1;
}
// Notify the other threads waiting for the initialization at start().
startTimeInitialized.countDown();
do {
final long deadline = waitForNextTick();
if (deadline > 0) {
int idx = (int) (tick & mask);
processCancelledTasks();
HashedWheelBucket bucket =
wheel[idx];
transferTimeoutsToBuckets();
bucket.expireTimeouts(deadline);
tick++;
}
} while (workerState.get() == WORKER_STATE_STARTED);
// Fill the unprocessedTimeouts so we can return them from stop() method.
for (HashedWheelBucket bucket : wheel) {
bucket.clearTimeouts(unprocessedTimeouts);
}
for (; ; ) {
HashedWheelTimeout timeout = timeouts.poll();
if (timeout == null) {
break;
}
if (!timeout.isCancelled()) {
unprocessedTimeouts.add(timeout);
}
}
processCancelledTasks();
}
private void transferTimeoutsToBuckets() {
// transfer only max. 100000 timeouts per tick to prevent a thread to stale the workerThread when it just
// adds new timeouts in a loop.
for (int i = 0; i < 100000; i++) {
HashedWheelTimeout timeout = timeouts.poll();
if (timeout == null) {
// all processed
break;
}
if (timeout.state() == HashedWheelTimeout.ST_CANCELLED) {
// Was cancelled in the meantime.
continue;
}
long calculated = timeout.deadline / tickDuration;
timeout.remainingRounds = (calculated - tick) / wheel.length;
final long ticks = Math.max(calculated, tick); // Ensure we don't schedule for past.
int stopIndex = (int) (ticks & mask);
HashedWheelBucket bucket = wheel[stopIndex];
bucket.addTimeout(timeout);
}
}
private void processCancelledTasks() {
for (; ; ) {
HashedWheelTimeout timeout = cancelledTimeouts.poll();
if (timeout == null) {
// all processed
break;
}
try {
timeout.remove();
} catch (Throwable e) {
e.printStackTrace();
}
}
}
/**
* calculate goal nanoTime from startTime and current tick number,
* then wait until that goal has been reached.
*
* @return Long.MIN_VALUE if received a shutdown request,
* current time otherwise (with Long.MIN_VALUE changed by +1)
*/
private long waitForNextTick() {
long deadline = tickDuration * (tick + 1);
for (; ; ) {
final long currentTime = System.nanoTime() - startTime;
long sleepTimeMs = (deadline - currentTime + 999999) / 1000000;
if (sleepTimeMs <= 0) {
if (currentTime == Long.MIN_VALUE) {
return -Long.MAX_VALUE;
} else {
return currentTime;
}
}
try {
//noinspection BusyWait
Thread.sleep(sleepTimeMs);
} catch (InterruptedException ignored) {
if (workerState.get() == WORKER_STATE_SHUTDOWN) {
return Long.MIN_VALUE;
}
}
}
}
public Set<Timeout> unprocessedTimeouts() {
return Collections.unmodifiableSet(unprocessedTimeouts);
}
}
private static final class HashedWheelTimeout implements Timeout {
private static final int ST_INIT = 0;
private static final int ST_CANCELLED = 1;
private static final int ST_EXPIRED = 2;
private static final AtomicIntegerFieldUpdater<HashedWheelTimeout> STATE_UPDATER =
AtomicIntegerFieldUpdater.newUpdater(HashedWheelTimeout.class, "state");
private final HashedWheelTimer timer;
private final TimerTask task;
private final long deadline;
@SuppressWarnings({"unused", "FieldMayBeFinal", "RedundantFieldInitialization"})
private volatile int state = ST_INIT;
// remainingRounds will be calculated and set by Worker.transferTimeoutsToBuckets() before the
// HashedWheelTimeout will be added to the correct HashedWheelBucket.
long remainingRounds;
// This will be used to chain timeouts in HashedWheelTimerBucket via a double-linked-list.
// As only the workerThread will act on it there is no need for synchronization / volatile.
HashedWheelTimeout next;
HashedWheelTimeout prev;
// The bucket to which the timeout was added
HashedWheelBucket bucket;
HashedWheelTimeout(HashedWheelTimer timer, TimerTask task, long deadline) {
this.timer = timer;
this.task = task;
this.deadline = deadline;
}
@Override
public Timer timer() {
return timer;
}
@Override
public TimerTask task() {
return task;
}
@Override
public boolean cancel() {
// only update the state it will be removed from HashedWheelBucket on next tick.
if (!compareAndSetState(ST_INIT, ST_CANCELLED)) {
return false;
}
// If a task should be canceled we put this to another queue which will be processed on each tick.
// So this means that we will have a GC latency of max. 1 tick duration which is good enough. This way
// we can make again use of our MpscLinkedQueue and so minimize the locking / overhead as much as possible.
timer.cancelledTimeouts.add(this);
return true;
}
void remove() {
HashedWheelBucket bucket = this.bucket;
if (bucket != null) {
bucket.remove(this);
} else {
timer.pendingTimeouts.decrementAndGet();
}
}
public boolean compareAndSetState(int expected, int state) {
return STATE_UPDATER.compareAndSet(this, expected, state);
}
public int state() {
return state;
}
@Override
public boolean isCancelled() {
return state() == ST_CANCELLED;
}
@Override
public boolean isExpired() {
return state() == ST_EXPIRED;
}
public void expire() {
if (!compareAndSetState(ST_INIT, ST_EXPIRED)) {
return;
}
try {
task.run(this);
} catch (Throwable t) {
t.printStackTrace();
}
}
@Override
public String toString() {
final long currentTime = System.nanoTime();
long remaining = deadline - currentTime + timer.startTime;
StringBuilder buf = new StringBuilder(192)
.append("HashedWheelTimer(deadline: ");
if (remaining > 0) {
buf.append(remaining)
.append(" ns later");
} else if (remaining < 0) {
buf.append(-remaining)
.append(" ns ago");
} else {
buf.append("now");
}
if (isCancelled()) {
buf.append(", cancelled");
}
return buf.append(", task: ")
.append(task())
.append(')')
.toString();
}
}
/**
* Bucket that stores HashedWheelTimeouts. These are stored in a linked-list like datastructure to allow easy
* removal of HashedWheelTimeouts in the middle. Also the HashedWheelTimeout act as nodes themself and so no
* extra object creation is needed.
*/
private static final class HashedWheelBucket {
// Used for the linked-list datastructure
private HashedWheelTimeout head;
private HashedWheelTimeout tail;
/**
* Add {@link HashedWheelTimeout} to this bucket.
*/
public void addTimeout(HashedWheelTimeout timeout) {
assert timeout.bucket == null;
timeout.bucket = this;
if (head == null) {
head = tail = timeout;
} else {
tail.next = timeout;
timeout.prev = tail;
tail = timeout;
}
}
/**
* Expire all {@link HashedWheelTimeout}s for the given {@code deadline}.
*/
public void expireTimeouts(long deadline) {
HashedWheelTimeout timeout = head;
// process all timeouts
while (timeout != null) {
HashedWheelTimeout next = timeout.next;
if (timeout.remainingRounds <= 0) {
next = remove(timeout);
if (timeout.deadline <= deadline) {
timeout.expire();
} else {
// The timeout was placed into a wrong slot. This should never happen.
throw new IllegalStateException(String.format(
"timeout.deadline (%d) > deadline (%d)", timeout.deadline, deadline));
}
} else if (timeout.isCancelled()) {
next = remove(timeout);
} else {
timeout.remainingRounds--;
}
timeout = next;
}
}
public HashedWheelTimeout remove(HashedWheelTimeout timeout) {
HashedWheelTimeout next = timeout.next;
// remove timeout that was either processed or cancelled by updating the linked-list
if (timeout.prev != null) {
timeout.prev.next = next;
}
if (timeout.next != null) {
timeout.next.prev = timeout.prev;
}
if (timeout == head) {
// if timeout is also the tail we need to adjust the entry too
if (timeout == tail) {
tail = null;
head = null;
} else {
head = next;
}
} else if (timeout == tail) {
// if the timeout is the tail modify the tail to be the prev node.
tail = timeout.prev;
}
// null out prev, next and bucket to allow for GC.
timeout.prev = null;
timeout.next = null;
timeout.bucket = null;
timeout.timer.pendingTimeouts.decrementAndGet();
return next;
}
/**
* Clear this bucket and return all not expired / cancelled {@link Timeout}s.
*/
public void clearTimeouts(Set<Timeout> set) {
for (; ; ) {
HashedWheelTimeout timeout = pollTimeout();
if (timeout == null) {
return;
}
if (timeout.isExpired() || timeout.isCancelled()) {
continue;
}
set.add(timeout);
}
}
private HashedWheelTimeout pollTimeout() {
HashedWheelTimeout head = this.head;
if (head == null) {
return null;
}
HashedWheelTimeout next = head.next;
if (next == null) {
tail = this.head = null;
} else {
this.head = next;
next.prev = null;
}
// null out prev and next to allow for GC.
head.next = null;
head.prev = null;
head.bucket = null;
return head;
}
}
}

View File

@@ -0,0 +1,37 @@
package com.jd.platform.async.openutil.timer;
/**
* 借鉴netty。
* 一个连接着{@link Timer}和{@link TimerTask},表示着任务状态的“关系类”
*
* @author create by TcSnZh on 2021/5/9-下午6:33
*/
public interface Timeout {
/**
* 返回对应的{@link Timer}。
*/
Timer timer();
/**
* 返回对应的{@link TimerTask}
*/
TimerTask task();
/**
* 当且仅当关联的{@link TimerTask}已超时时,才返回{@code true}。
*/
boolean isExpired();
/**
* 当且仅当关联的{@link TimerTask}被取消时,才返回{@code true}。
*/
boolean isCancelled();
/**
* 尝试取消关联的{@link TimerTask}。如果任务已经执行或已取消,它将无副作用地返回。
*
* @return 如果取消成功完成则为true否则为false
*/
@SuppressWarnings("unused")
boolean cancel();
}

View File

@@ -0,0 +1,43 @@
package com.jd.platform.async.openutil.timer;
import java.util.Set;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
/**
* 照抄netty
* 让{@link TimerTask}在后台线程中执行。
*
* @author create by TcSnZh on 2021/5/9-下午6:33
*/
public interface Timer {
/**
* 使{@link TimerTask}在指定的延迟后执行一次。
*
* @param delay 延时长度
* @param unit 延时单位
* @return 返回 {@link Timeout}关系类
* @throws IllegalStateException 如果此计时器已经已停止
* @throws RejectedExecutionException 如果挂起的超时太多,则创建新的超时会导致系统不稳定。
*/
Timeout newTimeout(TimerTask task, long delay, TimeUnit unit);
@SuppressWarnings("unused")
default Timeout newTimeout(Runnable runnable, long delay, TimeUnit unit) {
AtomicReference<Timeout> timeoutRef = new AtomicReference<>();
newTimeout(timeout -> {
timeoutRef.set(timeout);
runnable.run();
}, delay, unit);
return timeoutRef.get();
}
/**
* 释放此{@link Timer}所有资源(例如线程),并取消所有尚未执行的任务。
*
* @return 与被该方法取消的任务相关联的 {@link Timeout}
*/
Set<? extends Timeout> stop();
}

View File

@@ -0,0 +1,10 @@
package com.jd.platform.async.openutil.timer;
/**
* 类似于netty的TimerTask。
*
* @author create by TcSnZh on 2021/5/9-下午5:17
*/
public interface TimerTask{
void run(Timeout timeout) throws Exception;
}

View File

@@ -0,0 +1,51 @@
package openutiltest;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 便于测试的jdk动态代理
*
* @author create by TcSnZh on 2021/5/16-下午11:38
*/
public class PrintProxy<I> {
public PrintProxy(Class<I> clazz) {
this.interfaceClazz = clazz;
}
private final Class<?> interfaceClazz;
public I proxyTo(I obj, String objNickName) {
//noinspection unchecked
return (I) Proxy.newProxyInstance(
obj.getClass().getClassLoader(),
new Class[]{interfaceClazz},
(proxy, method, args) -> {
String methodInfo = methodInfo(method);
try {
Object res = method.invoke(obj, args);
System.out.printf(objNickName + " 执行方法: %-40s --> 方法返回值: %-20s --> this.toString() = %-40s\n",
methodInfo, res, obj);
return res;
} catch (Exception e) {
System.err.printf(objNickName + " 执行方法: %-40s --> 异常信息: %-40s --> this.toString() = %-40s\n",
methodInfo, e.getClass().getSimpleName() + " : " + e.getMessage(), obj
);
throw e;
}
}
);
}
private static String methodInfo(Method method) {
StringBuilder sb = new StringBuilder().append(method.getName()).append('(');
for (Class<?> parameterType : method.getParameterTypes()) {
sb.append(parameterType.getSimpleName()).append(", ");
}
if (method.getParameterTypes().length > 0) {
sb.delete(sb.length() - 2, sb.length());
}
return sb.append(')').toString();
}
}

View File

@@ -0,0 +1,37 @@
package openutiltest;
import com.jd.platform.async.openutil.collection.CommonDirectedGraph;
import com.jd.platform.async.openutil.collection.DirectedGraph;
import java.util.Arrays;
/**
* 测试图工具类的使用
*
* @author create by TcSnZh on 2021/5/16-下午11:25
*/
class TestGraph {
public static void main(String[] args) {
test_CommonDirectedGraph();
}
private static void test_CommonDirectedGraph() {
System.out.println("\n\n ==================== 测试正常使用 ==================");
//noinspection unchecked
DirectedGraph<String, String> graph =
new PrintProxy<>(DirectedGraph.class).proxyTo(new CommonDirectedGraph<>(), "graph");
graph.isDirected();
graph.addNode("胖虎");
graph.addNode("大雄");
graph.putRelation("胖虎", "", "大雄");
graph.addNode("静香");
graph.nodesView().addAll(Arrays.asList("小夫", "胖虎的妹妹", "哆啦A梦"));
graph.putRelation("胖虎", "是其哥", "胖虎的妹妹");
graph.putRelation("胖虎的妹妹", "是其妹", "胖虎");
graph.putRelation("胖虎的妹妹", "喜欢", "大雄");
graph.putRelation("胖虎", "????", "小夫");
graph.putRelation("大雄", "喜欢", "静香");
graph.removeNode("大雄");
graph.getRelations();
}
}

View File

@@ -6,7 +6,8 @@
<groupId>com.jd.platform</groupId>
<artifactId>asyncTool</artifactId>
<version>1.4.1-SNAPSHOT</version>
<packaging>pom</packaging>
<version>1.5.1-SNAPSHOT</version>
<build>
<plugins>
@@ -21,4 +22,8 @@
</plugin>
</plugins>
</build>
<modules>
<module>asyncTool-openutil</module>
<module>asyncTool-core</module>
</modules>
</project>

View File

@@ -1,28 +0,0 @@
package com.jd.platform.async.callback;
import com.jd.platform.async.worker.WorkResult;
/**
* 每个执行单元执行完毕后,会回调该接口</p>
* 需要监听执行结果的,实现该接口即可
*
* @author wuweifeng wrote on 2019-11-19.
*/
@FunctionalInterface
public interface ICallback<T, V> {
/**
* 任务开始的监听
*/
default void begin() {
}
/**
* 耗时操作执行完毕后就给value注入值
* <p/>
* 只要Wrapper被调用后成功或失败/超时,该方法都会被执行。
*/
void result(boolean success, T param, WorkResult<V> workResult);
}

View File

@@ -1,720 +0,0 @@
package com.jd.platform.async.wrapper;
import com.jd.platform.async.callback.DefaultCallback;
import com.jd.platform.async.callback.ICallback;
import com.jd.platform.async.callback.IWorker;
import com.jd.platform.async.exception.SkippedException;
import com.jd.platform.async.executor.timer.SystemClock;
import com.jd.platform.async.worker.*;
import com.jd.platform.async.wrapper.skipstrategy.SkipStrategy;
import com.jd.platform.async.wrapper.actionstrategy.DependMustStrategyMapper;
import com.jd.platform.async.wrapper.actionstrategy.DependWrapperStrategyMapper;
import com.jd.platform.async.wrapper.actionstrategy.DependenceAction;
import com.jd.platform.async.wrapper.actionstrategy.DependenceStrategy;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 对每个worker及callback进行包装一对一
* <p/>
* v1.5时将其抽取为抽象类,以解耦并提高扩展性。
*
* @author wuweifeng wrote on 2019-11-19.
*/
public abstract class WorkerWrapper<T, V> {
/**
* 该wrapper的唯一标识
*/
protected final String id;
/**
* worker将来要处理的param
*/
protected T param;
protected IWorker<T, V> worker;
protected ICallback<T, V> callback;
/**
* 标记该事件是否已经被处理过了譬如已经超时返回false了后续rpc又收到返回值了则不再二次回调
* 经试验,volatile并不能保证"同一毫秒"内,多线程对该值的修改和拉取
* <p>
* 1-finish, 2-error, 3-working
*/
protected final AtomicInteger state = new AtomicInteger(0);
/**
* 也是个钩子变量,用来存临时的结果
*/
protected volatile WorkResult<V> workResult = WorkResult.defaultResult();
/**
* 该map存放所有wrapper的id和wrapper映射
* <p/>
* 需要线程安全。
*/
private Map<String, WorkerWrapper<?, ?>> forParamUseWrappers;
/**
* 各种策略的封装类。
* <p/>
* 其实是因为加功能太多导致这个对象大小超过了128Byte所以强迫症的我不得不把几个字段丢到策略类里面去。
* ps: 大小超过128Byte令我(TcSnZh)难受的一比,就像走在草坪的格子上,一步嫌小、两步扯蛋。
* IDEA可以使用JOL Java Object Layout插件查看对象大小。
*/
private final WrapperStrategy wrapperStrategy = new WrapperStrategy();
/**
* 超时检查该值允许为null。表示不设置。
*/
private volatile TimeOutProperties timeOutProperties;
// ***** state属性的常量值 *****
public static final int FINISH = 1;
public static final int ERROR = 2;
public static final int WORKING = 3;
public static final int INIT = 0;
WorkerWrapper(String id, IWorker<T, V> worker, T param, ICallback<T, V> callback) {
if (worker == null) {
throw new NullPointerException("async.worker is null");
}
this.worker = worker;
this.param = param;
this.id = id;
//允许不设置回调
if (callback == null) {
callback = new DefaultCallback<>();
}
this.callback = callback;
}
// ========== public ==========
/**
* 外部调用本线程运行此Wrapper的入口方法。
*
* @param executorService 该ExecutorService将成功运行后在nextWrapper有多个时被使用于多线程调用。
* @param remainTime 剩下的时间
* @param forParamUseWrappers 用于保存经过的wrapper的信息的Mapkey为id。
* @param inspector wrapper调度检查器
*/
public void work(ExecutorService executorService,
long remainTime,
Map<String, WorkerWrapper<?, ?>> forParamUseWrappers,
WrapperEndingInspector inspector) {
work(executorService, null, remainTime, forParamUseWrappers, inspector);
}
public String getId() {
return id;
}
public WorkResult<V> getWorkResult() {
return workResult;
}
public void setParam(T param) {
this.param = param;
}
public int getState() {
return state.get();
}
/**
* 获取之后的下游Wrapper
*/
public abstract Set<WorkerWrapper<?, ?>> getNextWrappers();
/**
* 使wrapper状态修改为超时失败。但如果已经执行完成则不会修改
* <p/>
* 本方法不会试图执行超时判定逻辑。
* 如果要执行超时逻辑判断,请用{@link TimeOutProperties#checkTimeOut(boolean)}并传入参数true。
*/
public void failNow() {
int state = getState();
if (state == INIT || state == WORKING) {
fastFail(state, null);
}
}
public WrapperStrategy getWrapperStrategy() {
return wrapperStrategy;
}
// ========== protected ==========
/**
* 快速失败
*
* @return 已经失败则返回false如果刚才设置为失败了则返回true。
*/
protected boolean fastFail(int expect, Exception e) {
//试图将它从expect状态,改成Error
if (!compareAndSetState(expect, ERROR)) {
return false;
}
//尚未处理过结果
if (checkIsNullResult()) {
if (e == null) {
workResult.setResultState(ResultState.TIMEOUT);
} else {
workResult.setResultState(ResultState.EXCEPTION);
workResult.setEx(e);
}
workResult.setResult(worker.defaultValue());
}
callback.result(false, param, workResult);
return true;
}
/**
* 判断{@link #state}状态是否是初始值。
*/
protected boolean checkIsNullResult() {
return ResultState.DEFAULT == workResult.getResultState();
}
protected boolean compareAndSetState(int expect, int update) {
return this.state.compareAndSet(expect, update);
}
/**
* 工作的核心方法。
*
* @param fromWrapper 代表这次work是由哪个上游wrapper发起的。如果是首个Wrapper则为null。
* @param remainTime 剩余时间。
*/
protected void work(ExecutorService executorService,
WorkerWrapper<?, ?> fromWrapper,
long remainTime,
Map<String, WorkerWrapper<?, ?>> forParamUseWrappers,
WrapperEndingInspector inspector) {
this.setForParamUseWrappers(forParamUseWrappers);
//将自己放到所有wrapper的集合里去
forParamUseWrappers.put(id, this);
long now = SystemClock.now();
//总的已经超时了,就快速失败,进行下一个
if (remainTime <= 0) {
fastFail(INIT, null);
beginNext(executorService, now, remainTime, inspector);
return;
}
//如果自己已经执行过了。
//可能有多个依赖,其中的一个依赖已经执行完了,并且自己也已开始执行或执行完毕。当另一个依赖执行完毕,又进来该方法时,就不重复处理了
if (getState() == FINISH || getState() == ERROR) {
beginNext(executorService, now, remainTime, inspector);
return;
}
// 判断是否要跳过自己,该方法可能会跳过正在工作的自己。
final WrapperStrategy wrapperStrategy = getWrapperStrategy();
if (wrapperStrategy.shouldSkip(getNextWrappers(), this, fromWrapper)) {
fastFail(INIT, new SkippedException());
beginNext(executorService, now, remainTime, inspector);
return;
}
//如果没有任何依赖,说明自己就是第一批要执行的
final Set<WorkerWrapper<?, ?>> dependWrappers = getDependWrappers();
if (dependWrappers == null || dependWrappers.size() == 0) {
fire();
beginNext(executorService, now, remainTime, inspector);
return;
}
DependenceAction.WithProperty judge = wrapperStrategy.judgeAction(dependWrappers, this, fromWrapper);
switch (judge.getDependenceAction()) {
case TAKE_REST:
inspector.reduceWrapper(this);
return;
case FAST_FAIL:
switch (judge.getResultState()) {
case TIMEOUT:
fastFail(INIT, null);
break;
case EXCEPTION:
fastFail(INIT, judge.getFastFailException());
break;
default:
fastFail(INIT, new RuntimeException("ResultState " + judge.getResultState() + " set to FAST_FAIL"));
break;
}
beginNext(executorService, now, remainTime, inspector);
break;
case START_WORK:
fire();
beginNext(executorService, now, remainTime, inspector);
break;
case JUDGE_BY_AFTER:
default:
inspector.reduceWrapper(this);
throw new IllegalStateException("策略配置错误不应当在WorkerWrapper中返回JUDGE_BY_AFTER或其他无效值 : this=" + this + ",fromWrapper=" + fromWrapper);
}
}
/**
* 进行下一个任务
*/
protected void beginNext(ExecutorService executorService, long now, long remainTime, WrapperEndingInspector inspector) {
//花费的时间
final long costTime = SystemClock.now() - now;
final long nextRemainTIme = remainTime - costTime;
Set<WorkerWrapper<?, ?>> nextWrappers = getNextWrappers();
if (nextWrappers == null) {
inspector.setWrapperEndWithTryPolling(this);
return;
}
// nextWrappers只有一个就用本线程继续跑。
if (nextWrappers.size() == 1) {
try {
WorkerWrapper<?, ?> next = nextWrappers.stream().findFirst().get();
inspector.addWrapper(next);
next.work(executorService, WorkerWrapper.this, nextRemainTIme, getForParamUseWrappers(), inspector);
} finally {
inspector.setWrapperEndWithTryPolling(this);
}
return;
}
// nextWrappers有多个
try {
inspector.addWrapper(nextWrappers);
nextWrappers.forEach(next -> executorService.submit(() ->
next.work(executorService, this, nextRemainTIme, getForParamUseWrappers(), inspector))
);
} finally {
inspector.setWrapperEndWithTryPolling(this);
}
}
/**
* 本工作线程执行自己的job.判断阻塞超时这里开始时会判断一次总超时时间但在轮询线程会判断单个wrapper超时时间并也会判断总超时时间。
*/
protected void fire() {
//阻塞取结果
//避免重复执行
if (!checkIsNullResult()) {
return;
}
try {
//如果已经不是init状态了说明正在被执行或已执行完毕。这一步很重要可以保证任务不被重复执行
if (!compareAndSetState(INIT, WORKING)) {
return;
}
V resultValue;
try {
callback.begin();
if (timeOutProperties != null) {
timeOutProperties.startWorking();
}
//执行耗时操作
resultValue = (V) worker.action(param, (Map) getForParamUseWrappers());
} finally {
if (timeOutProperties != null) {
timeOutProperties.endWorking();
}
}
//如果状态不是在working,说明别的地方已经修改了
if (!compareAndSetState(WORKING, FINISH)) {
return;
}
workResult.setResultState(ResultState.SUCCESS);
workResult.setResult(resultValue);
//回调成功
callback.result(true, param, workResult);
} catch (Exception e) {
//避免重复回调
if (!checkIsNullResult()) {
return;
}
fastFail(WORKING, e);
}
}
// ========== hashcode and equals ==========
@Override
public boolean equals(Object o) {
return super.equals(o);
}
/**
* {@code return id.hashCode();}返回id值的hashcode
*/
@Override
public int hashCode() {
// final String id can use to .hashcode() .
return id.hashCode();
}
// ========== Builder ==========
public static <T, V> WorkerWrapperBuilder<T, V> builder() {
return new Builder<>();
}
/**
* 自v1.5,该类被抽取到{@link StableWorkerWrapperBuilder}抽象类,兼容之前的版本。
*/
public static class Builder<W, C> extends StableWorkerWrapperBuilder<W, C, Builder<W, C>> {
/**
* @deprecated 建议使用 {@link #builder()}返回{@link WorkerWrapperBuilder}接口以调用v1.5之后的规范api
*/
@Deprecated
public Builder() {
}
}
// ========== package access methods , for example , some getter/setter that doesn't want to be public ==========
T getParam() {
return param;
}
IWorker<T, V> getWorker() {
return worker;
}
void setWorker(IWorker<T, V> worker) {
this.worker = worker;
}
ICallback<T, V> getCallback() {
return callback;
}
void setCallback(ICallback<T, V> callback) {
this.callback = callback;
}
void setState(int state) {
this.state.set(state);
}
Map<String, WorkerWrapper<?, ?>> getForParamUseWrappers() {
return forParamUseWrappers;
}
void setForParamUseWrappers(Map<String, WorkerWrapper<?, ?>> forParamUseWrappers) {
this.forParamUseWrappers = forParamUseWrappers;
}
void setWorkResult(WorkResult<V> workResult) {
this.workResult = workResult;
}
abstract void setNextWrappers(Set<WorkerWrapper<?, ?>> nextWrappers);
abstract Set<WorkerWrapper<?, ?>> getDependWrappers();
abstract void setDependWrappers(Set<WorkerWrapper<?, ?>> dependWrappers);
TimeOutProperties getTimeOut() {
return timeOutProperties;
}
void setTimeOut(TimeOutProperties timeOutProperties) {
this.timeOutProperties = timeOutProperties;
}
// ========== toString ==========
@Override
public String toString() {
final StringBuilder sb = new StringBuilder(200)
.append("WorkerWrapper{id=").append(id)
.append(", param=").append(param)
.append(", worker=").append(worker)
.append(", callback=").append(callback)
.append(", state=");
int state = this.state.get();
if (state == FINISH) {
sb.append("FINISH");
} else if (state == WORKING) {
sb.append("WORKING");
} else if (state == INIT) {
sb.append("INIT");
} else if (state == ERROR) {
sb.append("ERROR");
} else {
throw new IllegalStateException("unknown state : " + state);
}
sb
.append(", workResult=").append(workResult)
// 防止循环引用这里只输出相关Wrapper的id
.append(", forParamUseWrappers::getId=[");
getForParamUseWrappers().keySet().forEach(wrapperId -> sb.append(wrapperId).append(", "));
if (getForParamUseWrappers().keySet().size() > 0) {
sb.delete(sb.length() - 2, sb.length());
}
sb
.append("], dependWrappers::getId=[");
getDependWrappers().stream().map(WorkerWrapper::getId).forEach(wrapperId -> sb.append(wrapperId).append(", "));
if (getDependWrappers().size() > 0) {
sb.delete(sb.length() - 2, sb.length());
}
sb
.append("], nextWrappers::getId=[");
getNextWrappers().stream().map(WorkerWrapper::getId).forEach(wrapperId -> sb.append(wrapperId).append(", "));
if (getNextWrappers().size() > 0) {
sb.delete(sb.length() - 2, sb.length());
}
sb
.append("]")
.append(", wrapperStrategy=").append(getWrapperStrategy())
.append(", timeOutProperties=").append(getTimeOut())
.append('}');
return sb.toString();
}
public static class WrapperStrategy implements DependenceStrategy, SkipStrategy {
// ========== 这三个属性用来判断是否要开始工作 ==========
// 从前往后依次判断的顺序为 dependWrapperStrategyMapper -> dependMustStrategyMapper -> dependenceStrategy
/**
* 对特殊Wrapper专用的依赖响应策略。
* <b>该值允许为null</b>
*/
private DependWrapperStrategyMapper dependWrapperStrategyMapper;
/**
* 对必须完成的must的Wrapper的依赖响应策略。
* <b>该值允许为null</b>
* <p/>
* 这是一个不得不向历史妥协的属性。用于适配must开关方式。
*/
private DependMustStrategyMapper dependMustStrategyMapper;
/**
* 依赖响应全局策略。
*/
private DependenceStrategy dependenceStrategy;
@Override
public DependenceAction.WithProperty judgeAction(Set<WorkerWrapper<?, ?>> dependWrappers,
WorkerWrapper<?, ?> thisWrapper,
WorkerWrapper<?, ?> fromWrapper) {
// 如果存在依赖,则调用三层依赖响应策略进行判断
DependenceStrategy strategy = dependWrapperStrategyMapper;
if (dependMustStrategyMapper != null) {
strategy = strategy == null ? dependMustStrategyMapper : strategy.thenJudge(dependMustStrategyMapper);
}
if (dependenceStrategy != null) {
strategy = strategy == null ? dependenceStrategy : strategy.thenJudge(dependenceStrategy);
}
if (strategy == null) {
throw new IllegalStateException("配置无效三层判断策略均为null请开发者检查自己的Builder是否逻辑错误");
}
return strategy.judgeAction(dependWrappers, thisWrapper, fromWrapper);
}
public DependWrapperStrategyMapper getDependWrapperStrategyMapper() {
return dependWrapperStrategyMapper;
}
public void setDependWrapperStrategyMapper(DependWrapperStrategyMapper dependWrapperStrategyMapper) {
this.dependWrapperStrategyMapper = dependWrapperStrategyMapper;
}
public DependMustStrategyMapper getDependMustStrategyMapper() {
return dependMustStrategyMapper;
}
public void setDependMustStrategyMapper(DependMustStrategyMapper dependMustStrategyMapper) {
this.dependMustStrategyMapper = dependMustStrategyMapper;
}
public DependenceStrategy getDependenceStrategy() {
return dependenceStrategy;
}
public void setDependenceStrategy(DependenceStrategy dependenceStrategy) {
this.dependenceStrategy = dependenceStrategy;
}
// ========== 跳过策略 ==========
private SkipStrategy skipStrategy;
@Override
public boolean shouldSkip(Set<WorkerWrapper<?, ?>> nextWrappers, WorkerWrapper<?, ?> thisWrapper, WorkerWrapper<?, ?> fromWrapper) {
return skipStrategy != null && skipStrategy.shouldSkip(nextWrappers, thisWrapper, fromWrapper);
}
public SkipStrategy getSkipStrategy() {
return skipStrategy;
}
public void setSkipStrategy(SkipStrategy skipStrategy) {
this.skipStrategy = skipStrategy;
}
// ========== toString ==========
@Override
public String toString() {
return "WrapperStrategy{" +
"dependWrapperStrategyMapper=" + dependWrapperStrategyMapper +
", dependMustStrategyMapper=" + dependMustStrategyMapper +
", dependenceStrategy=" + dependenceStrategy +
", skipStrategy=" + skipStrategy +
'}';
}
}
public static class TimeOutProperties {
private final boolean enable;
private final long time;
private final TimeUnit unit;
private final boolean allowInterrupt;
private final WorkerWrapper<?, ?> wrapper;
private final Object lock = new Object();
private volatile boolean started = false;
private volatile boolean ended = false;
private volatile long startWorkingTime;
private volatile long endWorkingTime;
private volatile Thread doWorkingThread;
public TimeOutProperties(boolean enable, long time, TimeUnit unit, boolean allowInterrupt, WorkerWrapper<?, ?> wrapper) {
this.enable = enable;
this.time = time;
this.unit = unit;
this.allowInterrupt = allowInterrupt;
this.wrapper = wrapper;
}
// ========== 工作线程调用 ==========
public void startWorking() {
synchronized (lock) {
started = true;
startWorkingTime = SystemClock.now();
doWorkingThread = Thread.currentThread();
}
}
public void endWorking() {
synchronized (lock) {
ended = true;
doWorkingThread = null;
endWorkingTime = SystemClock.now();
}
}
// ========== 轮询线程调用 ==========
/**
* 检查超时。
* 可以将boolean参数传入true以在超时的时候直接失败。
*
* @param withStop 如果为false不会发生什么仅仅是单纯的判断是否超时。
* 如果为true则会去快速失败wrapper{@link #failNow()},有必要的话还会打断线程。
* @return 如果 超时 或 执行时间超过限制 返回true未超时返回false。
*/
public boolean checkTimeOut(boolean withStop) {
if (enable) {
synchronized (lock) {
if (started) {
// 判断执行中的wrapper是否超时
long dif = (ended ? endWorkingTime : SystemClock.now()) - startWorkingTime;
if (dif > unit.toMillis(time)) {
if (withStop) {
if (allowInterrupt) {
doWorkingThread.interrupt();
}
wrapper.failNow();
ended = true;
}
return true;
}
return false;
}
}
}
return false;
}
// ========== package ==========
boolean isEnable() {
return enable;
}
long getTime() {
return time;
}
TimeUnit getUnit() {
return unit;
}
boolean isAllowInterrupt() {
return allowInterrupt;
}
Object getLock() {
return lock;
}
boolean isStarted() {
return started;
}
void setStarted(boolean started) {
this.started = started;
}
boolean isEnded() {
return ended;
}
void setEnded(boolean ended) {
this.ended = ended;
}
long getStartWorkingTime() {
return startWorkingTime;
}
void setStartWorkingTime(long startWorkingTime) {
this.startWorkingTime = startWorkingTime;
}
long getEndWorkingTime() {
return endWorkingTime;
}
void setEndWorkingTime(long endWorkingTime) {
this.endWorkingTime = endWorkingTime;
}
Thread getDoWorkingThread() {
return doWorkingThread;
}
void setDoWorkingThread(Thread doWorkingThread) {
this.doWorkingThread = doWorkingThread;
}
// ========== toString ==========
@Override
public String toString() {
return "TimeOutProperties{" +
"enable=" + enable +
", time=" + time +
", unit=" + unit +
", allowInterrupt=" + allowInterrupt +
", wrapper::getId=" + wrapper.getId() +
", started=" + started +
", ended=" + ended +
", startWorkingTime=" + startWorkingTime +
", endWorkingTime=" + endWorkingTime +
", doWorkingThread=" + doWorkingThread +
'}';
}
}
}

View File

@@ -1,486 +0,0 @@
package com.jd.platform.async.wrapper;
import com.jd.platform.async.executor.timer.SystemClock;
import com.jd.platform.async.worker.WorkResult;
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.stream.Collectors;
/**
* 判断{@link WorkerWrapper}是否链路调用完成的轮询器。
* =================================================================================
* <p>
* 在v1.4及以前的版本,存在如下问题:
* >
* 在使用线程数量较少的线程池进行beginWork时调用WorkerWrapper#beginNext方法时
* 会因为本线程等待下游Wrapper执行完成而存在线程耗尽bug。线程池会死翘翘的僵住、动弹不得。
* >
* 例如仅有2个线程的线程池执行以下任务
* {@code
* <p>
* 这是旧版本(v1.4及以前)中可能会引发线程耗尽bug的情况在test/v15.dependnew中示例testThreadPolling_V14Bug说明了这个bug
* 线程数2
* A(5ms)--B1(10ms) ---|--> C1(5ms)
* . \ | (B1、B2全部完成可执行C1、C2)
* . ---> B2(20ms) --|--> C2(5ms)
* <p>
* }
* 线程1执行了A然后在{@link java.util.concurrent.CompletableFuture#allOf(CompletableFuture[])}等待B1与B2执行完成。
* 线程2执行了B1或B2中的一个也在allOf方法等待C1、C2完成。
* 结果没有线程执行C和B2了导致超时而死并且这个线程池线程有可能被耗尽。
* >
* v1.5的解决方案是,放弃使工作线程遭致阻塞的{@link java.util.concurrent.CompletableFuture}
* 而是让工作线程在工作前注册到本“完成检查器”{@link WrapperEndingInspector},然后交由轮询中心{@link PollingCenter}进行检查是否完成。
* </p>
* =================================================================================
* <p>
* 本类的工作原理:
* .
* 原理:
* (1)首先在Async代码中将主动运行的wrapper都保存到一个inspector{@link #addWrapper(WorkerWrapper)}
* (2)主动运行的wrapper于FINISH/ERROR时先异步submit所有下游wrapper在其执行时将自身(下游wrapper)保存到inspector
* (3)然后在异步submit完所有下游wrapper后将调用{@link #setWrapperEndWithTryPolling(WorkerWrapper)}方法,
* . 设置自己的{@link #wrappers}为true并呼叫轮询{@link PollingCenter#tryPolling()}。
* (4)在下游wrapper中经过策略器判断后
* . 若是不需要运行则把本wrapper计数-1{@link WrapperNode#count},若是计数<1则将{@link WrapperNode}移出{@link #wrappers}。
* . 若是需要运行,则运行之,然后跳转到 (2) 的情节。如此递归执行链路上所有需要执行的wrapper最后都会存在于{@link #wrappers}中。
* .
* 因此,若是存在任一其{@link WrapperNode#called}为false的wrapper则表示这条链路还没有调用完。
* 若是在{@link #wrappers}中所有的{@link WrapperNode#called}为true时即可判断出链路执行完毕了。
* </p>
*
* @author create by TcSnZh on 2021/5/5-下午3:22
*/
public class WrapperEndingInspector implements Comparable<WrapperEndingInspector> {
/**
* 最迟完成时间
*/
private final long latestFinishTime;
/**
* 保存 需要检查的wrapper--相关属性 的Map。
*/
private final ConcurrentHashMap<WorkerWrapper, WrapperNode> wrappers = new ConcurrentHashMap<>();
/**
* 当全部wrapper都调用结束它会countDown
*/
private final CountDownLatch endCDL = new CountDownLatch(1);
/**
* 读锁用于修改数据写锁用于轮询。使用公平锁让wrapper的时间波动不会太长。
* <p/>
* 在轮询到本inspector时之所以要上写锁是因为
* 假如此时有个Wrapper正在调用{@link #addWrapper(WorkerWrapper)}则wrappers发生了改变。
* 假如现在恰巧访问到的是{@link #wrappers}迭代器的最后一个,但此时又加入了另一个,且这另一个又是需要去执行的。
* 那么假如在迭代器遍历到目前访问到的wrapper都是呼叫完毕的那么这新加入的一个就会被忽略从而判定为全部完成。致使bug发生。
* <p/>
* 此外,即便轮询时上写锁,对性能的影响也是有限的。因为这只会在“呼叫别人”的时候发生工作线程与轮询线程的锁争抢,
* 而在工作线程执行{@link com.jd.platform.async.callback.IWorker#action(Object, Map)}或
* {@link com.jd.platform.async.callback.ICallback#result(boolean, Object, WorkResult)}时,并不会与轮询线程去
* 争抢锁,而通常这个工作的时间才是最耗时的。
*/
private final ReentrantReadWriteLock modifyPollingLock = new ReentrantReadWriteLock(true);
/**
* 当轮询发现超时时该值被设为false
*/
private final AtomicBoolean haveNotTimeOut = new AtomicBoolean(true);
public WrapperEndingInspector(long latestFinishTime) {
this.latestFinishTime = latestFinishTime;
}
public void registerToPollingCenter() {
modifyPollingLock.readLock().lock();
try {
// 不重复put以免InspectorNode被替换为另一个
PollingCenter.getInstance().inspectionMap.putIfAbsent(this, new PollingCenter.InspectorNode());
} finally {
modifyPollingLock.readLock().unlock();
}
}
public void addWrapper(WorkerWrapper wrapper) {
modifyPollingLock.readLock().lock();
try {
wrappers.computeIfAbsent(wrapper, k -> new WrapperNode()).count.incrementAndGet();
} finally {
modifyPollingLock.readLock().unlock();
}
}
public void addWrapper(Collection<? extends WorkerWrapper> wrappers) {
modifyPollingLock.readLock().lock();
try {
Objects.requireNonNull(wrappers).forEach(this::addWrapper);
} finally {
modifyPollingLock.readLock().unlock();
}
}
public void reduceWrapper(WorkerWrapper wrapper) {
modifyPollingLock.readLock().lock();
try {
/*
* 有可能发生这情况一个Wrapper刚被加进去执行了零/一/多次,均不满足执行条件,但是下次调用却应当使其启动。
*/
if (wrapper.getState() != WorkerWrapper.INIT) {
final WrapperNode wrapperNode = wrappers.get(wrapper);
if (wrapperNode == null) {
return;
}
synchronized (wrapperNode) {
if (wrapperNode.count.decrementAndGet() < 1) {
wrappers.remove(wrapper);
}
}
}
} finally {
modifyPollingLock.readLock().unlock();
}
}
/**
* 原子的设置这个Wrapper已经呼叫完成了。
* <p/>
* 该方法会调用{@link PollingCenter#tryPolling()},呼叫轮询线程
*
* @return 如果为true表示设置成功。为false表示已经被设置过了。
*/
public boolean setWrapperEndWithTryPolling(WorkerWrapper wrapper) {
modifyPollingLock.readLock().lock();
try {
return !wrappers.get(wrapper).called.getAndSet(true);
} finally {
modifyPollingLock.readLock().unlock();
PollingCenter.getInstance().tryPolling();
}
}
/**
* 供外部调用的等待方法
*
* @return 在超时前完成返回true。超时时间一到就会返回false。就像人被杀就会死。
* @throws InterruptedException 外部调用的当前线程被中断时,会抛出这个异常。
*/
public boolean await() throws InterruptedException {
endCDL.await();
return haveNotTimeOut.get();
}
/**
* {@link PollingCenter}会优先把最迟完成时间(即开始时间+超时时间较早的Inspection放在前面。
*/
@Override
public int compareTo(WrapperEndingInspector other) {
if (this.latestFinishTime - other.latestFinishTime < 0) {
return -1;
}
return 1;
}
@Override
public String toString() {
return "WrapperEndingInspector{" +
"remainTime=" + (latestFinishTime - SystemClock.now()) +
", wrappers=" +
wrappers.entrySet().stream()
.collect(Collectors.toMap(entry -> entry.getKey().getId(), Map.Entry::getValue))
+
", endCDL.getCount()=" + endCDL.getCount() +
", writePollingLock={read=" + modifyPollingLock.getReadLockCount() + ",write=" + modifyPollingLock.getWriteHoldCount() +
"} }";
}
/**
* 节点对象,保存属性信息于{@link #wrappers}中。
* <p/>
* 当试图把Node移出本Map时该Node对象自身将会被上锁。
*/
public static class WrapperNode {
/**
* 是否已经呼叫完了下游wrapper
*/
AtomicBoolean called = new AtomicBoolean(false);
/**
* 本wrapper总共被呼叫次数的统计。若小于1则会被移出map。
*/
AtomicInteger count = new AtomicInteger(0);
@Override
public String toString() {
return "{" +
"called=" + called.get() +
", count=" + count.get() +
'}';
}
}
/**
* 轮询中心。具体的轮询调度由其完成。
* <p/>
* {@link #registerToPollingCenter()}调用时就会将inspector注册到本轮询中心以供轮询。
*/
public static class PollingCenter {
public static class InspectorNode {
/**
* 延迟轮询时间戳。
*/
private volatile long delayTimeStamp = Long.MAX_VALUE;
private final ReadWriteLock lockOfDelayTimeStamp = new ReentrantReadWriteLock();
/**
* 比较传入时间戳与{@link #delayTimeStamp},并设置小的那个为{@link #delayTimeStamp}的值。
*
* @param otherDelayTimeStamp 试图用来比较的另一个时间戳
*/
public void compareAndSetMinDelayTimeStamp(long otherDelayTimeStamp) {
lockOfDelayTimeStamp.writeLock().lock();
try {
long dif = otherDelayTimeStamp - delayTimeStamp;
if (dif > 0) {
return;
}
delayTimeStamp = otherDelayTimeStamp;
} finally {
lockOfDelayTimeStamp.writeLock().unlock();
}
}
public long getDelayTimeStamp() {
lockOfDelayTimeStamp.readLock().lock();
try {
return delayTimeStamp;
} finally {
lockOfDelayTimeStamp.readLock().unlock();
}
}
public long clearTimeStamp() {
lockOfDelayTimeStamp.writeLock().lock();
try {
long old = this.delayTimeStamp;
delayTimeStamp = Long.MAX_VALUE;
return old;
} finally {
lockOfDelayTimeStamp.writeLock().unlock();
}
}
@Override
public String toString() {
return "InspectorNode{" +
"delayTimeStamp=" + delayTimeStamp +
", lockOfDelayTimeStamp=" + lockOfDelayTimeStamp +
'}';
}
}
/**
* 将被轮询的WrapperFinishInspection集合。
*/
private final Map<WrapperEndingInspector, InspectorNode> inspectionMap = new ConcurrentSkipListMap<>();
/**
* 请求轮询。
*/
private void tryPolling() {
// 开始轮询
SINGLETON_POLLING_POOL.submit(() -> {
// 用来判断在轮询过程中是否有新增的inspector的值
int expectCount;
// 如果此值变化过,则在结束时让自己在此值后的时间再启动轮询
while (!inspectionMap.isEmpty()) {
// expectCount是本线程用来记录本次循环开始时inspectionMap的个数。
// 每当移出一个inspector时该值-1。
expectCount = inspectionMap.size();
// 开始检查
for (Map.Entry<WrapperEndingInspector, InspectorNode> entry : inspectionMap.entrySet()) {
final WrapperEndingInspector inspector = entry.getKey();
final InspectorNode inspectorNode = entry.getValue();
// 直接抢锁轮询期间禁止修改inspector
inspector.modifyPollingLock.writeLock().lock();
try {
// 对一个inspector进行检查
if (PollingCenter.this.checkInspectorIsEnd(inspector, inspectorNode)) {
// inspector中的wrapper调用结束了
// 先要把wrapper给停了
inspector.wrappers.forEach((wrapper, wrapperNode) -> {
WorkerWrapper.TimeOutProperties timeOut = wrapper.getTimeOut();
if (timeOut != null) {
timeOut.checkTimeOut(true);
}
});
// 修改此inspector和expectCount的状态
if (inspector.endCDL.getCount() > 0) {
// 双重检查使endCDL原子性countDown。
synchronized (inspector.endCDL) {
if (inspector.endCDL.getCount() > 0) {
inspectionMap.remove(inspector);
expectCount--;
inspector.endCDL.countDown();
}
}
}
}
} finally {
inspector.modifyPollingLock.writeLock().unlock();
}
}
/*
* 根据 expectCount == inspectionMap.size() 的值在仅有本线程1个线程在轮询的情况下
* 1. 若值为true表示轮询过程中没有新的inspector被添加进set中。此时就可以break了。
* . 之所以可以break是因为这个inspection还没有调用结束在其结束前还会来催促轮询的。
* 2. 若值为false表示有新的inspector在本线程轮询时被加入到了set中且没有被我们迭代到。此时还要重新轮询一次。
*/
if (expectCount == inspectionMap.size()) {
break;
}
}
});
}
private boolean checkInspectorIsEnd(WrapperEndingInspector inspector, InspectorNode inspectorNode) {
// 判断一下inspector整组是否超时
if (inspector.latestFinishTime < SystemClock.now()) {
inspector.haveNotTimeOut.set(false);
inspector.wrappers.forEach(((wrapper, wrapperNode) -> {
wrapper.failNow();
wrapperNode.called.set(true);
}));
return true;
}
// 将延迟检查时间设为离现在最近的值。
// 此处判断的是inspector所代表整次任务的超时时间
inspectorNode.compareAndSetMinDelayTimeStamp(inspector.latestFinishTime);
// 判断inspector是否结束并顺便记录、判断、修改wrapper的超时信息
for (Map.Entry<WorkerWrapper, WrapperNode> entry : inspector.wrappers.entrySet()) {
WorkerWrapper wrapper = entry.getKey();
// 判断单个wrapper是否超时
WorkerWrapper.TimeOutProperties timeOutProperties = wrapper.getTimeOut();
if (timeOutProperties != null && timeOutProperties.isEnable()) {
// 将延迟检查时间设为离现在最近的值。
// 此处判断的是wrapper的超时时间
if (timeOutProperties.checkTimeOut(true)) {
inspector.haveNotTimeOut.set(false);
}
// 未超时但是设置了超时检查的话记录一下inspector延时轮询时间
else {
inspectorNode.compareAndSetMinDelayTimeStamp(
(timeOutProperties.isStarted() ? timeOutProperties.getStartWorkingTime() : SystemClock.now())
+ timeOutProperties.getUnit().toMillis(timeOutProperties.getTime())
);
}
}
// 判断wrapper是否执行完毕
WrapperNode node = entry.getValue();
if (wrapper.getState() == WorkerWrapper.INIT
// 上值如果为false表示该Wrapper要么还没来得及执行要么判断不需要执行但是还未被移出
|| !node.called.get()
// 上值如果为false表示该Wrapper正在工作或是刚刚结束/失败还未将所有下游Wrapper调用一遍。
) {
return false;
}
}
return true;
}
{
final String executorName = "asyncTool-pollingDelayCaller";
ScheduledThreadPoolExecutor delayPollingExecutor = new ScheduledThreadPoolExecutor(
1,
new ThreadFactory() {
private final AtomicLong threadCount = new AtomicLong(0);
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r, executorName + "-thread-" + threadCount.getAndIncrement());
t.setDaemon(true);
// 线程优先级不高
t.setPriority(1);
return t;
}
@Override
public String toString() {
return executorName + "-threadFactory";
}
}
) {
@Override
public String toString() {
return executorName + "{PollingCenter.this=" + PollingCenter.this + "}";
}
};
// 每毫秒判断一次map.value的每个延迟轮询队列的头号元素是否抵达当前时间如果到了则清除并调用轮询
delayPollingExecutor.scheduleAtFixedRate(() -> inspectionMap.values().stream()
.min(Comparator.comparingLong(InspectorNode::getDelayTimeStamp))
.ifPresent(node -> {
long delayTimeStamp = node.getDelayTimeStamp();
if (Long.MAX_VALUE != delayTimeStamp && SystemClock.now() > delayTimeStamp) {
tryPolling();
}
}), 1, 1, TimeUnit.MILLISECONDS);
}
// ========== static ==========
private final static PollingCenter instance = new PollingCenter();
public static PollingCenter getInstance() {
return instance;
}
/**
* 单线程的轮询线程池
*/
private static final ThreadPoolExecutor SINGLETON_POLLING_POOL;
static {
SINGLETON_POLLING_POOL = new ThreadPoolExecutor(
0,
// 轮询线程数必须为1
1,
15L,
TimeUnit.SECONDS,
// 必须保存至少一个轮询请求,以便在本线程轮询结束时,获取到已轮询过的线程提交的轮询请求
new ArrayBlockingQueue<>(1),
new ThreadFactory() {
private final AtomicLong threadCount = new AtomicLong(0);
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r, "asyncTool-pollingCenterPool-thread-" + threadCount.getAndIncrement());
t.setDaemon(true);
// 线程优先级不高
t.setPriority(3);
return t;
}
@Override
public String toString() {
return "asyncTool-pollingCenterPool-threadFactory";
}
},
// 多的就丢了,反正都是催这一个线程去轮询
new ThreadPoolExecutor.DiscardPolicy()
) {
@Override
public String toString() {
return "asyncTool-pollingCenterPool";
}
};
}
}
}

View File

@@ -1,183 +0,0 @@
package com.jd.platform.async.wrapper.skipstrategy;
import com.jd.platform.async.wrapper.WorkerWrapper;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author create by TcSnZh on 2021/5/6-下午3:02
*/
@FunctionalInterface
public interface SkipStrategy {
/**
* 跳过策略函数。返回true将会使WorkerWrapper跳过执行。
*
* @param nextWrappers 下游WrapperSet
* @param thisWrapper 本WorkerWrapper
* @param fromWrapper 呼叫本Wrapper的上游Wrapper
* @return 返回true将会使WorkerWrapper跳过执行。
*/
boolean shouldSkip(Set<WorkerWrapper<?, ?>> nextWrappers, WorkerWrapper<?, ?> thisWrapper, WorkerWrapper<?, ?> fromWrapper);
/**
* 不跳过
*/
SkipStrategy NOT_SKIP = new SkipStrategy() {
@Override
public boolean shouldSkip(Set<WorkerWrapper<?, ?>> nextWrappers, WorkerWrapper<?, ?> thisWrapper, WorkerWrapper<?, ?> fromWrapper) {
return false;
}
@Override
public String toString() {
return "NOT_SKIP";
}
};
SkipStrategy CHECK_ONE_LEVEL = new SkipStrategy() {
private final SkipStrategy searchNextOneLevel = searchNextWrappers(SearchNextWrappers.SearchType.DFS, 1);
@Override
public boolean shouldSkip(Set<WorkerWrapper<?, ?>> nextWrappers, WorkerWrapper<?, ?> thisWrapper, WorkerWrapper<?, ?> fromWrapper) {
return searchNextOneLevel.shouldSkip(nextWrappers, thisWrapper, fromWrapper);
}
@Override
public String toString() {
return "CHECK_ONE_LEVEL";
}
};
default SearchNextWrappers searchNextWrappers(SearchNextWrappers.SearchType searchType, int searchLevel) {
return new SearchNextWrappers(searchType, searchLevel);
}
/**
* 检查之后的Wrapper是否不在INIT状态
*/
class SearchNextWrappers implements SkipStrategy {
/**
* 搜索策略
*/
enum SearchType {
DFS, BFS;
}
private final SearchType searchType;
/**
* 搜索深度
*/
private final int searchLevel;
public SearchNextWrappers(SearchType searchType, int searchLevel) {
this.searchType = Objects.requireNonNull(searchType);
this.searchLevel = searchLevel;
}
@Override
public boolean shouldSkip(Set<WorkerWrapper<?, ?>> nextWrappers, WorkerWrapper<?, ?> thisWrapper, WorkerWrapper<?, ?> fromWrapper) {
Set<WorkerWrapper<?, ?>> nextSet;
if ((nextSet = nextWrappers) == null || nextSet.isEmpty()) {
return false;
}
switch (searchType) {
case DFS:
return nextSet.stream().allMatch(next ->
next.getState() != WorkerWrapper.INIT || dfsSearchShouldSkip(next, 1));
case BFS:
LinkedList<BfsNode> queue = nextSet.stream().map(ww -> new BfsNode(ww, 0)).collect(Collectors.toCollection(LinkedList::new));
HashSet<WorkerWrapper<?, ?>> existed = new HashSet<>(nextSet);
while (!queue.isEmpty()) {
BfsNode node = queue.poll();
if (node.atLevel > searchLevel) {
continue;
}
if (node.wrapper.getState() != WorkerWrapper.INIT) {
return true;
}
if (node.atLevel < searchLevel) {
// 如果不是深度的最大值,则往队列里添加
node.wrapper.getNextWrappers().forEach(nextWrapper -> {
if (existed.contains(nextWrapper)) {
return;
}
queue.offer(new BfsNode(nextWrapper, node.atLevel + 1));
existed.add(nextWrapper);
});
}
}
return false;
default:
throw new IllegalStateException("searchType type illegal : " + searchType);
}
}
private boolean dfsSearchShouldSkip(WorkerWrapper<?, ?> currentWrapper, int currentLevel) {
if (currentLevel + 1 > searchLevel || currentWrapper == null) {
return false;
}
for (WorkerWrapper<?, ?> nextWrapper : currentWrapper.getNextWrappers()) {
if (nextWrapper != null &&
(nextWrapper.getState() != WorkerWrapper.INIT
|| dfsSearchShouldSkip(nextWrapper, currentLevel + 1))) {
return true;
}
}
return false;
}
static class BfsNode {
final WorkerWrapper<?, ?> wrapper;
final int atLevel;
public BfsNode(WorkerWrapper<?, ?> wrapper, int atLevel) {
this.wrapper = wrapper;
this.atLevel = atLevel;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
BfsNode bfsNode = (BfsNode) o;
return Objects.equals(wrapper, bfsNode.wrapper);
}
@Override
public int hashCode() {
return wrapper.hashCode();
}
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
SearchNextWrappers that = (SearchNextWrappers) o;
return searchLevel == that.searchLevel && searchType == that.searchType;
}
@Override
public int hashCode() {
return searchLevel ^ searchType.ordinal();
}
@Override
public String toString() {
return "CheckNextWrapper{" +
"searchType=" + searchType +
", searchLevel=" + searchLevel +
'}';
}
}
}