mirror of
https://gitee.com/jd-platform-opensource/asyncTool.git
synced 2026-03-22 04:27:15 +08:00
40
.gitignore
vendored
40
.gitignore
vendored
@@ -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/
|
||||
|
||||
552
QuickStart.md
552
QuickStart.md
@@ -4,6 +4,8 @@
|
||||
|
||||
代码不多,直接拷贝包过去即可。
|
||||
|
||||
#### 旧稳定版本v1.4
|
||||
|
||||
京东同事通过引用如下maven来使用。
|
||||
|
||||
```xml
|
||||
@@ -34,11 +36,49 @@
|
||||
</dependency>
|
||||
```
|
||||
|
||||
# 使用说明
|
||||
#### 最新版本v1.5(不稳定)
|
||||
|
||||
|
||||
|
||||
从gitee上下载仓库到本地,切换到`dev`分支,然后maven安装到本地仓库。
|
||||
|
||||
```bash
|
||||
git clone https://gitee.com/jd-platform-opensource/asyncTool.git
|
||||
cd ./asyncTool
|
||||
git checkout dev
|
||||
mvn install
|
||||
```
|
||||
|
||||
在项目中引入依赖。
|
||||
|
||||
```xml
|
||||
<!-- 任务编排核心包 -->
|
||||
<dependency>
|
||||
<artifactId>asyncTool-core</artifactId>
|
||||
<groupId>com.jd.platform</groupId>
|
||||
<version>1.5.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
# 任务编排
|
||||
|
||||
> `asyncTool-core`核心模块提供了核心功能——任务编排
|
||||
>
|
||||
> 以下文档基于版本:
|
||||
>
|
||||
> ```xml
|
||||
> <dependencies>
|
||||
> <dependency>
|
||||
> <groupId>com.jd.platform</groupId>
|
||||
> <artifactId>asyncTool-core</artifactId>
|
||||
> <version>1.5.1-SNAPSHOT</version>
|
||||
> </dependency>
|
||||
> </dependencies>
|
||||
> ```
|
||||
|
||||
### 基本组件
|
||||
|
||||
worker: 一个最小的任务执行单元。通常是一个网络调用,或一段耗时操作。
|
||||
`IWorker`: 一个最小的任务执行单元。通常是一个网络调用,或一段耗时操作。
|
||||
|
||||
T,V两个泛型,分别是入参和出参类型。
|
||||
|
||||
@@ -63,7 +103,7 @@ public interface IWorker<T, V> {
|
||||
V action(T object, Map<String, WorkerWrapper> allWrappers);
|
||||
|
||||
/**
|
||||
* 超时、异常时,返回的默认值
|
||||
* 超时、异常、跳过时,返回的默认值
|
||||
*
|
||||
* @return 默认值
|
||||
*/
|
||||
@@ -73,8 +113,7 @@ public interface IWorker<T, V> {
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
callBack:对每个worker的回调。worker执行完毕后,会回调该接口,带着执行成功、失败、原始入参、和详细的结果。
|
||||
`ICallback`:对每个worker的回调。worker执行完毕后,会回调该接口,带着执行成功、失败、原始入参、和详细的结果。
|
||||
|
||||
```java
|
||||
/**
|
||||
@@ -117,6 +156,85 @@ WorkerWrapper<String, String> w0 = WorkerWrapper.<String, String>builder()
|
||||
|
||||
通过这一个类看一下,action里就是你的耗时操作,begin就是任务开始执行时的回调,result就是worker执行完毕后的回调。当你组合了多个执行单元时,每一步的执行,都在掌控之内。失败了,还会有自定义的默认值。这是CompleteableFuture无法做到的。
|
||||
|
||||
### 如何构造WorkerWrapper?
|
||||
|
||||
##### 推荐Builder模式
|
||||
|
||||
如果刚开始使用这个框架,则推荐使用如下方式进行构造:
|
||||
|
||||
```java
|
||||
WorkerWrapper.<String, String>builder()
|
||||
.id()
|
||||
// 其他属性略。
|
||||
// 请在《简单示例》与《设置WorkerWrapper属性》中慢慢感受详细内容。
|
||||
// 因为这里地方小,写不下。
|
||||
```
|
||||
|
||||
##### 复杂的快速构造
|
||||
|
||||
> 不推荐新手使用。
|
||||
>
|
||||
> 不推荐在业务中使用,使用Builder模式代码更加简洁,且会检查参数,不必节省这些性能。
|
||||
>
|
||||
> 该对象的构造方法不会检查属性。
|
||||
|
||||
在对WorkerWrapper属性有充足了解后,可使用“直接设置属性 + 关系图”的方式快速构造wrapper。
|
||||
|
||||
建议在扩展功能的时候使用该构造器,以提高效率。但是请记得检查参数。
|
||||
|
||||
以下为示例:
|
||||
|
||||
```java
|
||||
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 : 省略
|
||||
*/
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 简单示例
|
||||
|
||||
1. 3个任务并行
|
||||
@@ -124,7 +242,7 @@ WorkerWrapper<String, String> w0 = WorkerWrapper.<String, String>builder()
|
||||

|
||||
|
||||
```java
|
||||
class Test {
|
||||
class Case0 {
|
||||
static WorkerWrapperBuilder<?, ?> builder(String id) {
|
||||
return WorkerWrapper.<String, String>builder()
|
||||
.id(id)
|
||||
@@ -139,15 +257,15 @@ class Test {
|
||||
WorkerWrapper<?, ?> b = builder("B").build();
|
||||
WorkerWrapper<?, ?> c = builder("C").build();
|
||||
try {
|
||||
Async.beginWork(100, a, b, c);
|
||||
} catch (ExecutionException | InterruptedException e) {
|
||||
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
|
||||
*/
|
||||
*/
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -158,7 +276,7 @@ class Test {
|
||||

|
||||
|
||||
```java
|
||||
class Test {
|
||||
class Case01 {
|
||||
static WorkerWrapperBuilder<?, ?> builder(String id) {
|
||||
return WorkerWrapper.<String, String>builder()
|
||||
.id(id)
|
||||
@@ -174,8 +292,8 @@ class Test {
|
||||
WorkerWrapper<?, ?> c = builder("C").depends(a).build();
|
||||
WorkerWrapper<?, ?> f = builder("F").depends(b, c).build();
|
||||
try {
|
||||
Async.beginWork(100, a);
|
||||
} catch (ExecutionException | InterruptedException e) {
|
||||
Async.work(100, a).awaitFinish();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
/* 输出:
|
||||
@@ -191,7 +309,7 @@ class Test {
|
||||
如果觉得`.depneds()`方法的排序您不喜欢,也可以用`.nextOf()`这种方式:
|
||||
|
||||
```java
|
||||
class Test {
|
||||
class Case02 {
|
||||
static WorkerWrapperBuilder<?, ?> builder(String id) {
|
||||
return WorkerWrapper.<String, String>builder()
|
||||
.id(id)
|
||||
@@ -208,8 +326,8 @@ class Test {
|
||||
.nextOf(builder("C").nextOf(f).build())
|
||||
.build();
|
||||
try {
|
||||
Async.beginWork(100, a);
|
||||
} catch (ExecutionException | InterruptedException e) {
|
||||
Async.work(100, a).awaitFinish();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
/* 输出:
|
||||
@@ -261,8 +379,8 @@ class Case1 {
|
||||
)
|
||||
.build();
|
||||
try {
|
||||
Async.beginWork(1000, a, d);
|
||||
} catch (ExecutionException | InterruptedException e) {
|
||||
Async.work(1000, a, d).awaitFinish();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
/* 输出:
|
||||
@@ -320,7 +438,7 @@ class Case2 {
|
||||
.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.beginWork(20,wrapper100,wrapper200);
|
||||
Async.work(20,wrapper100,wrapper200).awaitFinish();
|
||||
System.out.println(add.getWorkResult());
|
||||
// 输出WorkResult{result=300, resultState=SUCCESS, ex=null}
|
||||
}
|
||||
@@ -334,11 +452,16 @@ class Case2 {
|
||||
`Async`工具类有多个方法可以使用自定义线程池
|
||||
|
||||
```java
|
||||
public static boolean beginWork(long timeout,
|
||||
public static OnceWork work(long timeout,
|
||||
ExecutorService executorService,
|
||||
Collection<? extends WorkerWrapper<?,?>> workerWrappers);
|
||||
|
||||
public static boolean beginWork(long timeout, ExecutorService executorService, WorkerWrapper... workerWrapper);
|
||||
public static OnceWork work(long timeout, ExecutorService executorService, WorkerWrapper... workerWrapper);
|
||||
|
||||
public static OnceWork work(long timeout,
|
||||
ExecutorService executorService,
|
||||
Collection<? extends WorkerWrapper<?, ?>> workerWrappers,
|
||||
String workId);
|
||||
```
|
||||
|
||||
另外,如果没有指定线程池,默认会使用`COMMON_POOL`,您可以调用这些方法获得/关闭此线程池:
|
||||
@@ -353,19 +476,17 @@ public static ThreadPoolExecutor getCommonPool();
|
||||
|
||||
/**
|
||||
* @param now 是否立即关闭
|
||||
* @throws IllegalStateException 如果尚未调用过{@link #getCommonPool()},即没有使用过“使用默认线程池”的方法,该方法会抛出空指针异常。
|
||||
* @return 如果尚未调用过{@link #getCommonPool()},即没有初始化默认线程池,返回false。否则返回true。
|
||||
*/
|
||||
public static synchronized void shutDownCommonPool(boolean now);
|
||||
public static synchronized boolean shutDownCommonPool(boolean now);
|
||||
```
|
||||
|
||||
以下是一个使用自定义线程池的简单代码示例:
|
||||
|
||||
```java
|
||||
Async.beginWork(1000, Executors.newFixedThreadPool(2),a);
|
||||
Async.work(1000, Executors.newFixedThreadPool(2),a).awaitFinish();
|
||||
```
|
||||
|
||||
|
||||
|
||||
## WorkerWrapper基本属性
|
||||
|
||||
### 执行流程
|
||||
@@ -381,9 +502,116 @@ WorkerWrapper会在这些情况被运行:
|
||||
|
||||
> processOn流程图文件放在同仓库。
|
||||
|
||||
### 其他属性
|
||||
### 属性
|
||||
|
||||
#### id
|
||||
|
||||
`WorkerWrapper`的id属性非常重要。
|
||||
|
||||
可在builder的该属性设置id,如果不设置,默认使用UUID。
|
||||
|
||||
```java
|
||||
public interface WorkerWrapperBuilder<T, V> {
|
||||
/**
|
||||
* 设置唯一id。
|
||||
* 如果不设置,{@link StableWorkerWrapperBuilder}会使用UUID
|
||||
*/
|
||||
WorkerWrapperBuilder<T, V> id(String id);
|
||||
|
||||
// 略
|
||||
}
|
||||
```
|
||||
|
||||
例如如果你需要在`IWorker`中调用上游wrapper,则可以根据id来获取到。
|
||||
|
||||
> 该map的键即为`WorkerWrapper`的id。
|
||||
|
||||
```java
|
||||
V action(T object, Map<String, WorkerWrapper<?,?>> allWrappers);
|
||||
```
|
||||
|
||||
请程序员确保在一次任务执行的一组wrapper中,id不会重复。在执行过程中不会进行检查。
|
||||
|
||||
#### 其他省略
|
||||
|
||||
> 其他属性都写在源码注释中,可下载源码慢慢查看。
|
||||
|
||||
## `OnceWork`任务句柄详解
|
||||
|
||||
`Async.work(...)`方法的返回值为`OnceWork`句柄。
|
||||
|
||||
> 源码里有大量的注释,直接看源码效率更高
|
||||
|
||||
#### 需要同步等待完成
|
||||
|
||||
`OnceWork`被返回后,任务并没有同步完成,而是还在运行。
|
||||
|
||||
如果我们需要同步完成,则调用`awaitFinish`方法即可同步等待。
|
||||
|
||||
#### 取消任务
|
||||
|
||||
调用`pleaseCancel`方法可取消任务,以下为示例:
|
||||
|
||||
```java
|
||||
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为SKIP,workResult.ex为CancelSkippedException,即被取消了。
|
||||
不过有时程序运行慢,导致B被取消了,那么C就不会执行,其状态就为INIT了。
|
||||
*/
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 设置WorkerWrapper属性
|
||||
|
||||
@@ -455,7 +683,7 @@ class Case3 {
|
||||
// 这里用线程数较少的线程池做示例,对于ALL_DEPENDENCIES_ANY_SUCCESS“仅需一个”的效果会好一点
|
||||
ExecutorService pool = Executors.newFixedThreadPool(2);
|
||||
try {
|
||||
Async.beginWork(1000, pool, a);
|
||||
Async.work(1000, pool, a).awaitFinish();
|
||||
} finally {
|
||||
pool.shutdown();
|
||||
}
|
||||
@@ -466,6 +694,8 @@ class Case3 {
|
||||
wrapper(id=B2) is working
|
||||
wrapper(id=C2) is working
|
||||
wrapper(id=C1) is working
|
||||
wrapper(id=B4) is working
|
||||
// 我们看到B5被跳过了,没有执行callback
|
||||
*/
|
||||
}
|
||||
}
|
||||
@@ -531,62 +761,76 @@ public enum DependenceAction {
|
||||
| `FAST_FAIL` | 立即失败。WorkerWrapper会去执行快速失败的方法。 |
|
||||
| `JUDGE_BY_AFTER` | 交给下层`{@link DependenceStrategy}`进行判断。 由于`{@link DependenceStrategy#thenJudge(DependenceStrategy)}`的责任链设计模式,该返回值的意义就是调用责任链上下一个策略。 |
|
||||
|
||||
> 如果wrapper被跳过,ResultState将为`DEFAULT`。
|
||||
>
|
||||
>
|
||||
|
||||
##### 策略器组件默认实现
|
||||
|
||||
* `DependenceStrategy.ALL_DEPENDENCIES_ALL_SUCCESS`,该值为默认值,若builder未设置则默认使用这个。
|
||||
1. 被依赖的所有Wrapper都必须成功才能开始工作。
|
||||
2. 如果其中任一Wrapper还没有执行且不存在失败,则休息。
|
||||
3. 如果其中任一Wrapper失败则立即失败。
|
||||
3. 如果其中任一Wrapper失败则立即失败。*(跳过不算失败)*
|
||||
* `DependenceStrategy.ALL_DEPENDENCIES_ANY_SUCCESS`
|
||||
1. 被依赖的Wrapper中任意一个成功了就可以开始工作。
|
||||
2. 如果其中所有Wrapper还没有执行,则休息。
|
||||
3. 如果其中一个Wrapper失败且不存在成功则立即失败。
|
||||
3. 如果其中一个Wrapper失败且不存在成功则立即失败。*(跳过不算失败)*
|
||||
* `DependenceStrategy.ALL_DEPENDENCIES_NONE_FAILED`
|
||||
* 如果被依赖的工作中任一失败,则立即失败。否则就开始工作(不论之前的工作有没有开始)。
|
||||
* 如果被依赖的工作中任一失败,则立即失败。*(跳过不算失败)*
|
||||
* 否则就开始工作(不论之前的工作有没有开始)。
|
||||
* `DependenceStrategy.theseWrapperAllSuccess(Set<WorkerWrapper<?,?>>)`
|
||||
* 该方法传入一个`Set`指定wrapper,只有当指定的这些Wrapper都成功时,才会开始工作。任一失败会快速失败。任一还没有执行且不存在失败,则休息。
|
||||
* 不建议使用:~~`DependenceStrategy.IF_MUST_SET_NOT_EMPTY_ALL_SUCCESS_ELSE_ANY`~~
|
||||
* 此值用于适配v1.4及之前的must开关模式,当`wrapperStrategy`的`dependMustStrategyMapper`的`mustDependSet`不为空时,则休息(因为能判断到这个责任链说明set中存在不满足的值)。为空时,则任一成功则执行。
|
||||
|
||||
##### `WorkerWrapper`的三层策略器责任链
|
||||
##### `WorkerWrapper`的策略器责任链
|
||||
|
||||
`WorkerWrapper`在判断时,并不是只使用一个策略进行判断的,而是在`WorkerWrapper.WrapperStrategy`进行了最多三层的判断:
|
||||
`WorkerWrapper`在判断时,并不是只使用一个策略进行判断的,而是在`WrapperStrategy`进行了最多三层的判断:
|
||||
|
||||
```java
|
||||
public abstract class WorkerWrapper<T, V> {
|
||||
|
||||
// 略
|
||||
|
||||
public static class WrapperStrategy implements DependenceStrategy, SkipStrategy {
|
||||
// ========== 这三个策略器用于链式判断是否要开始工作 ==========
|
||||
public interface WrapperStrategy extends DependenceStrategy, SkipStrategy {
|
||||
// ========== 这三个策略器用于链式判断是否要开始工作 ==========
|
||||
|
||||
// 从前往后依次判断的顺序为 dependWrapperStrategyMapper -> dependMustStrategyMapper -> dependenceStrategy
|
||||
// 从前往后依次判断的顺序为 dependWrapperStrategyMapper -> dependMustStrategyMapper -> dependenceStrategy
|
||||
|
||||
/**
|
||||
* 对特殊Wrapper专用的依赖响应策略。
|
||||
* <b>该值允许为null</b>
|
||||
*/
|
||||
private DependWrapperStrategyMapper dependWrapperStrategyMapper;
|
||||
/**
|
||||
* 对必须完成的(must的)Wrapper的依赖响应策略。
|
||||
* <b>该值允许为null</b>
|
||||
* <p/>
|
||||
* 这是一个不得不向历史妥协的属性。用于适配must开关方式。
|
||||
*/
|
||||
private DependMustStrategyMapper dependMustStrategyMapper;
|
||||
/**
|
||||
* 底层全局策略。
|
||||
*/
|
||||
private DependenceStrategy dependenceStrategy;
|
||||
|
||||
// 略
|
||||
}
|
||||
/**
|
||||
* 设置对特殊Wrapper专用的依赖响应策略。
|
||||
*
|
||||
* @return 该值允许为null
|
||||
*/
|
||||
DependOnUpWrapperStrategyMapper getDependWrapperStrategyMapper();
|
||||
|
||||
/**
|
||||
* 对必须完成的(must的)Wrapper的依赖响应策略。
|
||||
* 这是一个不得不向历史妥协的属性。用于适配must开关方式。
|
||||
*
|
||||
* @return 该值允许为null
|
||||
*/
|
||||
DependMustStrategyMapper getDependMustStrategyMapper();
|
||||
|
||||
/**
|
||||
* 底层全局策略。
|
||||
*
|
||||
* @return 该值不允许为null
|
||||
*/
|
||||
DependenceStrategy getDependenceStrategy();
|
||||
|
||||
// ========== 这是跳过策略 ==========
|
||||
|
||||
/**
|
||||
* 跳过策略
|
||||
*
|
||||
* @return 不允许为null
|
||||
*/
|
||||
SkipStrategy getSkipStrategy();
|
||||
|
||||
// 其他属性略,自行查看源码即可
|
||||
}
|
||||
```
|
||||
|
||||
正如注释所言,三个策略器将依次调用`DependenceStrategy.judgeAction(Set,WorkerWrapper,WorkerWrapper)`方法进行判断,每次判断会返回`DependenceAction.WithProperty`类型。
|
||||
正如注释所言,三个策略器将依次调用`judgeAction(Set,WorkerWrapper,WorkerWrapper)`方法进行判断,每次判断会返回`DependenceAction.WithProperty`类型。
|
||||
|
||||
前两个策略器的返回值,即`DependenceAction.WithProperty`类型,若调用`getDependenceAction()`方法返回的枚举值不为`JUDGE_BY_AFTER`时,整个三层责任链将返回此返回值;若为`JUDGE_BY_AFTER`,则交给下个策略器进行判断。该方法具体由以下方法实现:
|
||||
前两个策略器的返回值若不为枚举`JUDGE_BY_AFTER`的内部类时,整个三层责任链将返回此返回值;若为`JUDGE_BY_AFTER`,则交给下个策略器进行判断。该方法具体由以下方法实现:
|
||||
|
||||
```java
|
||||
public interface DependenceStrategy {
|
||||
@@ -670,7 +914,7 @@ class Case4 {
|
||||
}
|
||||
ExecutorService pool = Executors.newFixedThreadPool(2);
|
||||
try {
|
||||
Async.beginWork(1000, pool, a);
|
||||
Async.work(1000, pool, a).awaitFinish();
|
||||
} finally {
|
||||
pool.shutdown();
|
||||
}
|
||||
@@ -759,7 +1003,7 @@ class Case5 {
|
||||
WorkerWrapper<?, ?> start = builder("start").nextOf(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10).build();
|
||||
ExecutorService pool = Executors.newFixedThreadPool(2);
|
||||
try {
|
||||
Async.beginWork(1000, pool, start);
|
||||
Async.work(1000, pool, start).awaitFinish();
|
||||
} finally {
|
||||
pool.shutdown();
|
||||
}
|
||||
@@ -788,74 +1032,51 @@ class Case5 {
|
||||
|
||||
那么,能不能让上游wrapper根据自己的状态独自决定下游wrapper响应呢?
|
||||
|
||||
因此,三层策略器的`DependWrapperStrategyMapper`便是用于设置此功能的。
|
||||
可以。`DependOnUpWrapperStrategy`函数式接口 与 `DependOnUpWrapperStrategyMapper`这两个类即可完成这个功能。
|
||||
|
||||
```java
|
||||
// 示例版本v1.5
|
||||
|
||||
/**
|
||||
* 对不同的{@link WorkerWrapper}调用者实行个性化依赖响应策略。
|
||||
* <p/>
|
||||
* 使用{@link DependWrapperStrategyMapper}本实现类对{@link DependenceStrategy}进行增强,
|
||||
* 由上游wrapper决定本wrapper行为的单参数策略。
|
||||
*
|
||||
* @author create by TcSnZh on 2021/5/1-下午11:12
|
||||
* @author create by TcSnZh on 2021/5/1-下午11:16
|
||||
*/
|
||||
public class DependWrapperStrategyMapper implements DependenceStrategy {
|
||||
private final Map<WorkerWrapper<?, ?>, DependWrapperActionStrategy> mapper = new ConcurrentHashMap<>(4);
|
||||
|
||||
/**
|
||||
* 设置对应策略
|
||||
*
|
||||
* @param targetWrapper 要设置策略的WorkerWrapper
|
||||
* @param strategy 要设置的策略
|
||||
* @return 返回this,链式调用。
|
||||
*/
|
||||
public DependWrapperStrategyMapper putMapping(WorkerWrapper<?, ?> targetWrapper, DependWrapperActionStrategy strategy) {/* 略 */}
|
||||
|
||||
/**
|
||||
* 判断方法。
|
||||
* <p/>
|
||||
* 如果fromWrapper在{@link #mapper}中,则返回{@link DependWrapperActionStrategy}的判断返回值。否则返回{@link DependenceAction#JUDGE_BY_AFTER}
|
||||
*
|
||||
* @param dependWrappers (这里不会使用该值)thisWrapper.dependWrappers的属性值。
|
||||
* @param thisWrapper (这里不会使用该值)thisWrapper,即为“被催促”的WorkerWrapper
|
||||
* @param fromWrapper 调用来源Wrapper。
|
||||
* @return 如果在mapper中有对fromWrapper的处理策略,则使用其进行判断。否则返回JUDGE_BY_AFTER交给下一个进行判断。
|
||||
*/
|
||||
@Override
|
||||
public DependenceAction.WithProperty judgeAction(
|
||||
Set<WorkerWrapper<?,?>> dependWrappers,
|
||||
WorkerWrapper<?, ?> thisWrapper,
|
||||
WorkerWrapper<?, ?> fromWrapper // 仅判断该属性
|
||||
) {/* 略 */}
|
||||
|
||||
// 略
|
||||
}
|
||||
```
|
||||
|
||||
其`mapper`属性中,每个`WorkerWrapper<?, ?>`对应了一个`DependWrapperActionStrategy`,这个接口便是用于让上游wrapper决定下游响应的:
|
||||
|
||||
```java
|
||||
@FunctionalInterface
|
||||
public interface DependWrapperActionStrategy {
|
||||
public interface DependOnUpWrapperStrategy {
|
||||
/**
|
||||
* 仅使用一个参数的判断方法
|
||||
* 仅使用一个参数(即调用自身的上游wrapper)的判断方法
|
||||
*
|
||||
* @param fromWrapper 调用本Wrapper的上游Wrapper
|
||||
* @return 返回 {@link DependenceAction.WithProperty}
|
||||
*/
|
||||
DependenceAction.WithProperty judge(WorkerWrapper<?, ?> fromWrapper);
|
||||
|
||||
// 常量略
|
||||
|
||||
// ========== 送几个供链式调用的默认值 ==========
|
||||
|
||||
/**
|
||||
* 成功时,交给下一个策略器判断。
|
||||
* 未运行时,休息。
|
||||
* 失败时,失败。
|
||||
*/
|
||||
DependOnUpWrapperStrategy SUCCESS_CONTINUE = /*略*/ ;
|
||||
/**
|
||||
* 成功时,开始工作。
|
||||
* 未运行时,交给下一个策略器判断。
|
||||
* 失败时,失败。
|
||||
*/
|
||||
DependOnUpWrapperStrategy SUCCESS_START_INIT_CONTINUE = /*略*/ ;
|
||||
}
|
||||
```
|
||||
|
||||
###### 提供常量
|
||||
在`DependOnUpWrapperStrategyMapper`的`mapper`属性中,每个`WorkerWrapper<?, ?>`对应了一个`DependOnUpWrapperStrategy`,实现了让wrapper对不同的上游做出不同的响应策略。
|
||||
|
||||
* `DependWrapperActionStrategy.SUCCESS_CONTINUE`
|
||||
* 成功时,交给下一个策略器判断。未运行时,休息。失败时,失败。
|
||||
* `DependWrapperActionStrategy SUCCESS_START_INIT_CONTINUE`
|
||||
* 成功时,开始工作。未运行时,交给下一个策略器判断。失败时,失败。
|
||||
```java
|
||||
public class DependOnUpWrapperStrategyMapper implements DependenceStrategy {
|
||||
private final Map<WorkerWrapper<?, ?>, DependOnUpWrapperStrategy> mapper = new ConcurrentHashMap<>(4);
|
||||
// 以下略
|
||||
}
|
||||
```
|
||||
|
||||
在《`WorkerWrapper`的三层策略器责任链》这一章中,我们可以看到,第一层策略器就是此`DependOnUpWrapperStrategyMapper`。
|
||||
|
||||
###### 简单使用与示例
|
||||
|
||||
@@ -892,34 +1113,35 @@ SetNext<T, V> specialToNextWrapper(DependWrapperActionStrategy strategy, WorkerW
|
||||
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;
|
||||
});
|
||||
.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<?, ?> b = builder("B")
|
||||
// 这里设置了,不论a怎么样b都会快速失败。但是,a设置的对wrapper的特殊策略把它覆盖了。
|
||||
.depends((dependWrappers, thisWrapper, fromWrapper) ->
|
||||
DependenceAction.FAST_FAIL
|
||||
.fastFailException(ResultState.EXCEPTION, new RuntimeException("b 必定失败,除非有上游wrapper救他"))
|
||||
)
|
||||
.build();
|
||||
// 这里设置了,不论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.beginWork(1000, 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());
|
||||
/* 输出:
|
||||
@@ -932,7 +1154,12 @@ class Case6 {
|
||||
}
|
||||
```
|
||||
|
||||
###### 提供常量
|
||||
|
||||
* `DependWrapperActionStrategy.SUCCESS_CONTINUE`
|
||||
* 成功时,交给下一个策略器判断。未运行时,休息。失败时,失败。
|
||||
* `DependWrapperActionStrategy SUCCESS_START_INIT_CONTINUE`
|
||||
* 成功时,开始工作。未运行时,交给下一个策略器判断。失败时,失败。
|
||||
|
||||
### 设置跳过策略
|
||||
|
||||
@@ -943,8 +1170,9 @@ class Case6 {
|
||||
```json
|
||||
{
|
||||
result: null,
|
||||
resultState: ResultState.EXCEPTION,
|
||||
ex: com.jd.platform.async.exception.SkippedException
|
||||
// 注意:如果wrapper被跳过,ResultState将为DEFAULT
|
||||
resultState: "ResultState.DEFAULT",
|
||||
ex: "com.jd.platform.async.exception.SkippedException"
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1018,7 +1246,7 @@ class Case7 {
|
||||
.build(),
|
||||
builder("E", 5).nextOf(d).build()
|
||||
).build();
|
||||
Async.beginWork(1000, a);
|
||||
Async.work(1000, a).awaitFinish();
|
||||
/* 输出:
|
||||
wrapper(id=A) is working
|
||||
wrapper(id=E) is working
|
||||
@@ -1139,7 +1367,7 @@ class Case8 {
|
||||
.nextOf(builder("C", 20).build())
|
||||
.build())
|
||||
.build();
|
||||
Async.beginWork(15, a);
|
||||
Async.work(20, a).awaitFinish();
|
||||
/* 输出:
|
||||
wrapper(id=A) has begin .
|
||||
wrapper(id=A) is working
|
||||
@@ -1151,14 +1379,13 @@ class Case8 {
|
||||
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)
|
||||
...
|
||||
以下异常信息省略
|
||||
*/
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 设置是否允许被打断线程
|
||||
|
||||
可通过该选项去设置允许线程被打断:
|
||||
@@ -1178,15 +1405,50 @@ public interface WorkerWrapperBuilder<T, V> {
|
||||
}
|
||||
```
|
||||
|
||||
#### 线程会被打断的具体情况
|
||||
|
||||
开启之后,在以下情况,会试图打断正处于WORKING状态的工作线程。
|
||||
|
||||
* 总任务超时,但本wrapper在WORKING。
|
||||
* 单wrapper超时,但本wrapper在WORKING。
|
||||
* wrapper应当被跳过,但本wrapper在WORKING。
|
||||
|
||||
* 调用`WorkerWrapper#failNow()`方法,且wrapper在WORKING状态。
|
||||
|
||||
###
|
||||
# 开放工具类
|
||||
|
||||
> `asyncTool-openutil`工具模块提供了一些便于开发的工具类。
|
||||
>
|
||||
> 可单独引入依赖:
|
||||
>
|
||||
> ```xml
|
||||
> <dependencies>
|
||||
> <dependency>
|
||||
> <groupId>com.jd.platform</groupId>
|
||||
> <artifactId>asyncTool-openutil</artifactId>
|
||||
> <version>1.5.1-SNAPSHOT</version>
|
||||
> </dependency>
|
||||
> </dependencies>
|
||||
> ```
|
||||
|
||||
### 集合类
|
||||
|
||||
> 普通集合包`com.jd.platform.async.openutil.collection.*`
|
||||
|
||||
这里不详述,要用的话源码里有注释。
|
||||
|
||||
* `SparseArray2D` 稀疏矩阵。
|
||||
* `CommonDirectedGraph` 有向图。
|
||||
* `CommonStoreArk` id储物柜。
|
||||
|
||||
### 定时器
|
||||
|
||||
> `com.jd.platform.async.openutil.timer.*`
|
||||
|
||||
* `HashedWheelTimer` 从netty里抄来的时间轮工具类。
|
||||
|
||||
### 其他
|
||||
|
||||
> `com.jd.platform.async.openutil.*`
|
||||
|
||||
* `BiInt` 一个表示两个int值的实体类,内含缓冲区间、默认比较器,适合拿来当2维索引。
|
||||
|
||||
|
||||
13
README.md
13
README.md
@@ -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
27
asyncTool-core/pom.xml
Normal 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>
|
||||
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
46
asyncTool-core/src/main/java/com/jd/platform/async/callback/ICallback.java
Executable file
46
asyncTool-core/src/main/java/com/jd/platform/async/callback/ICallback.java
Executable 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";
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
/**
|
||||
* 每个最小执行单元需要实现该接口
|
||||
*
|
||||
@@ -20,7 +20,7 @@ public interface IWorker<T, V> {
|
||||
V action(T object, Map<String, WorkerWrapper<?,?>> allWrappers);
|
||||
|
||||
/**
|
||||
* 超时、异常时,返回的默认值
|
||||
* 超时、异常、跳过时,返回的默认值
|
||||
*
|
||||
* @return 默认值
|
||||
*/
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.jd.platform.async.exception;
|
||||
|
||||
import com.jd.platform.async.executor.timer.SystemClock;
|
||||
|
||||
/**
|
||||
* 如果任务在执行之前,自己后面的任务已经执行完或正在被执行,则抛该exception
|
||||
*
|
||||
@@ -7,11 +9,22 @@ package com.jd.platform.async.exception;
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
@@ -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.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,20 +26,65 @@ 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 ! ");
|
||||
WorkerWrapperGroup group = new WorkerWrapperGroup(SystemClock.now(), timeout);
|
||||
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) {
|
||||
@@ -44,37 +92,24 @@ public class Async {
|
||||
}
|
||||
executorService.submit(() -> wrapper.work(executorService, timeout, group));
|
||||
});
|
||||
return group.awaitFinish();
|
||||
//处理超时的逻辑被移动到了WrapperEndingInspector中。
|
||||
return onceWork;
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果想自定义线程池,请传pool。不自定义的话,就走默认的COMMON_POOL
|
||||
* @deprecated 已经被 {@link #work(long, ExecutorService, Collection, String)}方法取代。
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
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();
|
||||
@@ -125,7 +160,7 @@ public class Async {
|
||||
* 该线程池将会给线程取名为asyncTool-commonPool-thread-0(数字不重复)。
|
||||
* </p>
|
||||
*/
|
||||
private static ThreadPoolExecutor COMMON_POOL;
|
||||
private static volatile ThreadPoolExecutor COMMON_POOL;
|
||||
|
||||
/**
|
||||
* 在以前(及现在)的版本中:
|
||||
@@ -133,7 +168,7 @@ public class Async {
|
||||
* <p/>
|
||||
* 注意,这里是个static,也就是只能有一个线程池。用户自定义线程池时,也只能定义一个
|
||||
*/
|
||||
private static volatile ExecutorService lastExecutorService;
|
||||
private static final AtomicReference<ExecutorService> lastExecutorService = new AtomicReference<>(null);
|
||||
|
||||
/**
|
||||
* 该方法将会返回{@link #COMMON_POOL},如果还未初始化则会懒加载初始化后再返回。
|
||||
@@ -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;
|
||||
}
|
||||
@@ -183,11 +220,12 @@ public class Async {
|
||||
|
||||
/**
|
||||
* @param now 是否立即关闭
|
||||
* @throws IllegalStateException 如果尚未调用过{@link #getCommonPool()},即没有使用过“使用默认线程池”的方法,该方法会抛出空指针异常。
|
||||
* @return 如果尚未调用过{@link #getCommonPool()},即没有初始化默认线程池,返回false。否则返回true。
|
||||
*/
|
||||
public static synchronized void shutDownCommonPool(boolean now) {
|
||||
@SuppressWarnings("unused")
|
||||
public static synchronized boolean shutDownCommonPool(boolean now) {
|
||||
if (COMMON_POOL == null) {
|
||||
throw new IllegalStateException("COMMON_POOL Not initialized yet");
|
||||
return false;
|
||||
}
|
||||
if (!COMMON_POOL.isShutdown()) {
|
||||
if (now) {
|
||||
@@ -196,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);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -209,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,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();
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
package com.jd.platform.async.executor;
|
||||
|
||||
import com.jd.platform.async.util.timer.Timeout;
|
||||
import com.jd.platform.async.util.timer.TimerTask;
|
||||
import com.jd.platform.async.util.timer.HashedWheelTimer;
|
||||
import com.jd.platform.async.util.timer.Timer;
|
||||
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;
|
||||
@@ -12,7 +12,7 @@ import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 检查{@link WorkerWrapperGroup}是否调用完成的轮询中心。
|
||||
* <p>
|
||||
* 内部使用时间轮进行轮询。
|
||||
* <p>
|
||||
* ===========================================================================================
|
||||
* <p>
|
||||
@@ -27,11 +27,11 @@ import java.util.concurrent.TimeUnit;
|
||||
* 这是旧版本(v1.4及以前)中可能会引发线程耗尽bug的情况,在test/v15.wrappertest中示例testThreadPolling_V14Bug说明了这个bug
|
||||
* 线程数:2
|
||||
* A(5ms)--B1(10ms) ---|--> C1(5ms)
|
||||
* . \ | (B1、B2全部完成可执行C1、C2)
|
||||
* . \ | (B1、B2任一完成可执行C1、C2)
|
||||
* . ---> B2(20ms) --|--> C2(5ms)
|
||||
* <p>
|
||||
* }
|
||||
* 线程1执行了A,然后在{@link java.util.concurrent.CompletableFuture#allOf(CompletableFuture[])}等待B1与B2执行完成。
|
||||
* 线程1执行了A,然后在{@link CompletableFuture#allOf(CompletableFuture[])}等待B1与B2执行完成。
|
||||
* 线程2执行了B1或B2中的一个,也在allOf方法等待C1、C2完成。
|
||||
* 结果没有线程执行C和B2了,导致超时而死,并且这个线程池线程有可能被耗尽。
|
||||
* >
|
||||
@@ -65,7 +65,7 @@ public class PollingCenter {
|
||||
thread.setDaemon(true);
|
||||
return thread;
|
||||
},
|
||||
4,
|
||||
1,
|
||||
TimeUnit.MILLISECONDS,
|
||||
1024);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
package com.jd.platform.async.worker;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* 执行结果
|
||||
*/
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
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.strategy.depend.DependMustStrategyMapper;
|
||||
import com.jd.platform.async.wrapper.strategy.depend.DependWrapperActionStrategy;
|
||||
import com.jd.platform.async.wrapper.strategy.depend.DependWrapperStrategyMapper;
|
||||
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;
|
||||
|
||||
@@ -62,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;
|
||||
/**
|
||||
@@ -172,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;
|
||||
}
|
||||
@@ -232,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;
|
||||
}
|
||||
@@ -330,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) {
|
||||
@@ -341,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);
|
||||
}
|
||||
@@ -351,12 +353,12 @@ class StableWorkerWrapperBuilder<T, V, BUILDER_SUB_CLASS extends StableWorkerWra
|
||||
}
|
||||
if (selfIsSpecialMap != null && selfIsSpecialMap.size() > 0) {
|
||||
selfIsSpecialMap.forEach((next, strategy) -> {
|
||||
DependWrapperStrategyMapper dependWrapperStrategyMapper = next.getWrapperStrategy().getDependWrapperStrategyMapper();
|
||||
if (dependWrapperStrategyMapper == null) {
|
||||
DependOnUpWrapperStrategyMapper dependOnUpWrapperStrategyMapper = next.getWrapperStrategy().getDependWrapperStrategyMapper();
|
||||
if (dependOnUpWrapperStrategyMapper == null) {
|
||||
next.getWrapperStrategy().setDependWrapperStrategyMapper(
|
||||
dependWrapperStrategyMapper = new DependWrapperStrategyMapper());
|
||||
dependOnUpWrapperStrategyMapper = new DependOnUpWrapperStrategyMapper());
|
||||
}
|
||||
dependWrapperStrategyMapper.putMapping(wrapper, strategy);
|
||||
dependOnUpWrapperStrategyMapper.putMapping(wrapper, strategy);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -381,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) {
|
||||
@@ -397,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) {
|
||||
@@ -406,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) {
|
||||
@@ -477,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
|
||||
@@ -489,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;
|
||||
}
|
||||
|
||||
@@ -1,25 +1,41 @@
|
||||
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.worker.*;
|
||||
import com.jd.platform.async.wrapper.strategy.skip.SkipStrategy;
|
||||
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.DependWrapperStrategyMapper;
|
||||
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.*;
|
||||
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.*;
|
||||
|
||||
/**
|
||||
@@ -29,6 +45,7 @@ import static com.jd.platform.async.wrapper.WorkerWrapper.State.*;
|
||||
*
|
||||
* @author wuweifeng wrote on 2019-11-19.
|
||||
*/
|
||||
@SuppressWarnings("AlibabaAbstractClassShouldStartWithAbstractNaming")
|
||||
public abstract class WorkerWrapper<T, V> {
|
||||
// ========== 固定属性 ==========
|
||||
|
||||
@@ -41,7 +58,7 @@ public abstract class WorkerWrapper<T, V> {
|
||||
/**
|
||||
* 各种策略的封装类。
|
||||
*/
|
||||
private final WrapperStrategy wrapperStrategy = new WrapperStrategy();
|
||||
private final WrapperStrategy wrapperStrategy;
|
||||
/**
|
||||
* 是否允许被打断
|
||||
*/
|
||||
@@ -80,14 +97,14 @@ public abstract class WorkerWrapper<T, V> {
|
||||
*/
|
||||
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
|
||||
TimeUnit timeoutUnit,
|
||||
WrapperStrategy wrapperStrategy
|
||||
) {
|
||||
if (worker == null) {
|
||||
throw new NullPointerException("async.worker is null");
|
||||
@@ -103,7 +120,17 @@ public abstract class WorkerWrapper<T, V> {
|
||||
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 ==========
|
||||
@@ -141,7 +168,7 @@ public abstract class WorkerWrapper<T, V> {
|
||||
}
|
||||
|
||||
public State getState() {
|
||||
return State.of(state.get());
|
||||
return of(state.get());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -193,7 +220,7 @@ public abstract class WorkerWrapper<T, V> {
|
||||
// 就在想CAS的时候,出结果了,就采用新的结果重新判断一次
|
||||
continue;
|
||||
}
|
||||
fastFail(true, null);
|
||||
fastFail(true, null, false);
|
||||
}
|
||||
return -1L;
|
||||
}
|
||||
@@ -204,6 +231,16 @@ public abstract class WorkerWrapper<T, V> {
|
||||
} 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;
|
||||
}
|
||||
@@ -228,37 +265,39 @@ public abstract class WorkerWrapper<T, V> {
|
||||
// 因为抽取成方法反而不好传参、污染类方法,所以就这么干了
|
||||
final Consumer<Boolean> __function__callbackResult =
|
||||
success -> {
|
||||
WorkResult<V> _workResult = getWorkResult();
|
||||
try {
|
||||
callback.result(success, param, getWorkResult());
|
||||
callback.result(success, param, _workResult);
|
||||
} catch (Exception e) {
|
||||
if (State.setState(state, states_of_skipOrAfterWork, ERROR, null)) {
|
||||
fastFail(false, e);
|
||||
if (setState(state, states_of_skipOrAfterWork, ERROR, null)) {
|
||||
fastFail(false, e, _workResult.getEx() instanceof SkippedException);
|
||||
}
|
||||
}
|
||||
};
|
||||
final Runnable __function__callbackResult_beginNext =
|
||||
final Runnable __function__callbackResultOfFalse_beginNext =
|
||||
() -> {
|
||||
__function__callbackResult.accept(false);
|
||||
beginNext(executorService, now, remainTime, group);
|
||||
};
|
||||
final BiConsumer<Boolean, Exception> __function__fastFail_callbackResult_beginNext =
|
||||
final BiConsumer<Boolean, Exception> __function__fastFail_callbackResult$false_beginNext =
|
||||
(fastFail_isTimeout, fastFail_exception) -> {
|
||||
fastFail(fastFail_isTimeout, fastFail_exception);
|
||||
__function__callbackResult_beginNext.run();
|
||||
boolean isSkip = fastFail_exception instanceof SkippedException;
|
||||
fastFail(fastFail_isTimeout && !isSkip, fastFail_exception, isSkip);
|
||||
__function__callbackResultOfFalse_beginNext.run();
|
||||
};
|
||||
final Runnable __function__doWork =
|
||||
() -> {
|
||||
if (State.setState(state, STARTED, WORKING)) {
|
||||
if (setState(state, STARTED, WORKING)) {
|
||||
try {
|
||||
fire(group);
|
||||
} catch (Exception e) {
|
||||
if (State.setState(state, WORKING, ERROR)) {
|
||||
__function__fastFail_callbackResult_beginNext.accept(false, e);
|
||||
if (setState(state, WORKING, ERROR)) {
|
||||
__function__fastFail_callbackResult$false_beginNext.accept(false, e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (State.setState(state, WORKING, AFTER_WORK)) {
|
||||
if (setState(state, WORKING, AFTER_WORK)) {
|
||||
__function__callbackResult.accept(true);
|
||||
beginNext(executorService, now, remainTime, group);
|
||||
}
|
||||
@@ -266,20 +305,25 @@ public abstract class WorkerWrapper<T, V> {
|
||||
// ================================================
|
||||
// 开始执行
|
||||
try {
|
||||
if (State.isState(state, BUILDING)) {
|
||||
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 (State.setState(state, states_of_checkTimeoutAllowStates, ERROR, null)) {
|
||||
__function__fastFail_callbackResult_beginNext.accept(true, null);
|
||||
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 (!State.setState(state, states_of_notWorked, STARTED, oldStateRef::set)) {
|
||||
if (!setState(state, states_of_notWorked, STARTED, oldStateRef::set)) {
|
||||
return;
|
||||
}
|
||||
// 如果wrapper是第一次,要调用callback.begin
|
||||
@@ -288,8 +332,8 @@ public abstract class WorkerWrapper<T, V> {
|
||||
callback.begin();
|
||||
} catch (Exception e) {
|
||||
// callback.begin 发生异常
|
||||
if (State.setState(state, states_of_checkTimeoutAllowStates, ERROR, null)) {
|
||||
__function__fastFail_callbackResult_beginNext.accept(false, e);
|
||||
if (setState(state, states_of_beforeWorkingEnd, ERROR, null)) {
|
||||
__function__fastFail_callbackResult$false_beginNext.accept(false, e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -305,22 +349,23 @@ public abstract class WorkerWrapper<T, V> {
|
||||
// 每个线程都需要判断是否要跳过自己,该方法可能会跳过正在工作的自己。
|
||||
final WrapperStrategy wrapperStrategy = getWrapperStrategy();
|
||||
if (wrapperStrategy.shouldSkip(getNextWrappers(), this, fromWrapper)) {
|
||||
if (State.setState(state, STARTED, SKIP)) {
|
||||
__function__fastFail_callbackResult_beginNext.accept(false, new SkippedException());
|
||||
if (setState(state, STARTED, SKIP)) {
|
||||
__function__fastFail_callbackResult$false_beginNext.accept(false, new SkippedException());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果是由其他wrapper调用而运行至此,则使用策略器决定自己的行为
|
||||
DependenceAction.WithProperty judge = wrapperStrategy.judgeAction(getDependWrappers(), this, fromWrapper);
|
||||
DependenceAction.WithProperty judge =
|
||||
wrapperStrategy.judgeAction(getDependWrappers(), this, fromWrapper);
|
||||
switch (judge.getDependenceAction()) {
|
||||
case TAKE_REST:
|
||||
return;
|
||||
case FAST_FAIL:
|
||||
if (State.setState(state, STARTED, ERROR)) {
|
||||
if (setState(state, STARTED, ERROR)) {
|
||||
// 根据FAST_FAIL.fastFailException()设置的属性值来设置fastFail方法的参数
|
||||
ResultState resultState = judge.getResultState();
|
||||
__function__fastFail_callbackResult_beginNext.accept(
|
||||
__function__fastFail_callbackResult$false_beginNext.accept(
|
||||
resultState == ResultState.TIMEOUT,
|
||||
judge.getFastFailException()
|
||||
);
|
||||
@@ -331,14 +376,16 @@ public abstract class WorkerWrapper<T, V> {
|
||||
return;
|
||||
case JUDGE_BY_AFTER:
|
||||
default:
|
||||
throw new Error("策略配置错误,不应当在WorkerWrapper中返回JUDGE_BY_AFTER或其他无效值 : this=" + this + ",fromWrapper=" + fromWrapper);
|
||||
throw new IllegalStateException(
|
||||
"策略配置错误,不应当在WorkerWrapper中返回JUDGE_BY_AFTER或其他无效值 : this=" + this +
|
||||
",fromWrapper=" + fromWrapper);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// wrapper本身抛出了不该有的异常
|
||||
State.setState(state, states_all, ERROR, null);
|
||||
setState(state, states_all, ERROR, null);
|
||||
NotExpectedException ex = new NotExpectedException(e, this);
|
||||
workResult.set(new WorkResult<>(null, ResultState.EXCEPTION, ex));
|
||||
__function__fastFail_callbackResult_beginNext.accept(false, ex);
|
||||
__function__fastFail_callbackResult$false_beginNext.accept(false, ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -360,17 +407,16 @@ public abstract class WorkerWrapper<T, V> {
|
||||
} finally {
|
||||
doWorkingThread.set(null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 快速失败。
|
||||
* 该方法不负责检查状态,请自行控制。
|
||||
*
|
||||
* @param timeout 是否是因为超时而快速失败
|
||||
* @param e 设置异常信息到{@link WorkResult#getEx()}
|
||||
* @param isTimeout 是否是因为超时而快速失败
|
||||
* @param e 设置异常信息到{@link WorkResult#getEx()}
|
||||
*/
|
||||
protected void fastFail(boolean timeout, Exception e) {
|
||||
protected void fastFail(boolean isTimeout, Exception e, boolean isSkip) {
|
||||
// 试图打断正在执行{@link IWorker#action(Object, Map)}的线程
|
||||
Thread _doWorkingThread;
|
||||
if ((_doWorkingThread = doWorkingThread.get()) != null
|
||||
@@ -381,7 +427,7 @@ public abstract class WorkerWrapper<T, V> {
|
||||
// 尚未处理过结果则设置
|
||||
workResult.compareAndSet(null, new WorkResult<>(
|
||||
worker.defaultValue(),
|
||||
timeout ? ResultState.TIMEOUT : ResultState.EXCEPTION,
|
||||
isTimeout ? ResultState.TIMEOUT : (isSkip ? ResultState.DEFAULT : ResultState.EXCEPTION),
|
||||
e
|
||||
));
|
||||
}
|
||||
@@ -406,7 +452,7 @@ public abstract class WorkerWrapper<T, V> {
|
||||
try {
|
||||
next = nextWrappers.stream().findFirst().get();
|
||||
group.addWrapper(next);
|
||||
State.setState(state, AFTER_WORK, SUCCESS);
|
||||
setState(state, AFTER_WORK, SUCCESS);
|
||||
} finally {
|
||||
PollingCenter.getInstance().checkGroup(group.new CheckFinishTask());
|
||||
if (next != null) {
|
||||
@@ -421,7 +467,7 @@ public abstract class WorkerWrapper<T, V> {
|
||||
nextWrappers.forEach(next -> executorService.submit(() ->
|
||||
next.work(executorService, this, nextRemainTIme, group))
|
||||
);
|
||||
State.setState(state, AFTER_WORK, SUCCESS);
|
||||
setState(state, AFTER_WORK, SUCCESS);
|
||||
} finally {
|
||||
PollingCenter.getInstance().checkGroup(group.new CheckFinishTask());
|
||||
}
|
||||
@@ -429,8 +475,6 @@ public abstract class WorkerWrapper<T, V> {
|
||||
|
||||
}
|
||||
|
||||
// ========== private ==========
|
||||
|
||||
// ========== hashcode and equals ==========
|
||||
|
||||
@Override
|
||||
@@ -460,6 +504,7 @@ public abstract class WorkerWrapper<T, V> {
|
||||
/**
|
||||
* @deprecated 建议使用 {@link #builder()}返回{@link WorkerWrapperBuilder}接口,以调用v1.5之后的规范api
|
||||
*/
|
||||
@SuppressWarnings("DeprecatedIsStillUsed")
|
||||
@Deprecated
|
||||
public Builder() {
|
||||
}
|
||||
@@ -477,7 +522,7 @@ public abstract class WorkerWrapper<T, V> {
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder(400)
|
||||
.append("WorkerWrapper{id=").append(id)
|
||||
.append(", state=").append(State.of(state.get()))
|
||||
.append(", state=").append(of(state.get()))
|
||||
.append(", param=").append(param)
|
||||
.append(", workResult=").append(workResult)
|
||||
.append(", allowInterrupt=").append(allowInterrupt)
|
||||
@@ -507,99 +552,54 @@ public abstract class WorkerWrapper<T, V> {
|
||||
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开关方式。
|
||||
*/
|
||||
/**
|
||||
* 一个通用的策略器实现类,提供了修改的功能。并兼容之前的代码。
|
||||
*/
|
||||
public static class StableWrapperStrategy extends WrapperStrategy.AbstractWrapperStrategy {
|
||||
private DependOnUpWrapperStrategyMapper dependOnUpWrapperStrategyMapper;
|
||||
private DependMustStrategyMapper dependMustStrategyMapper;
|
||||
/**
|
||||
* 底层全局策略。
|
||||
*/
|
||||
private DependenceStrategy dependenceStrategy;
|
||||
private SkipStrategy skipStrategy;
|
||||
|
||||
@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 DependOnUpWrapperStrategyMapper getDependWrapperStrategyMapper() {
|
||||
return dependOnUpWrapperStrategyMapper;
|
||||
}
|
||||
|
||||
public DependWrapperStrategyMapper getDependWrapperStrategyMapper() {
|
||||
return dependWrapperStrategyMapper;
|
||||
}
|
||||
|
||||
public void setDependWrapperStrategyMapper(DependWrapperStrategyMapper dependWrapperStrategyMapper) {
|
||||
this.dependWrapperStrategyMapper = dependWrapperStrategyMapper;
|
||||
@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;
|
||||
}
|
||||
|
||||
// ========== 跳过策略 ==========
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSkipStrategy(SkipStrategy skipStrategy) {
|
||||
this.skipStrategy = skipStrategy;
|
||||
}
|
||||
|
||||
// ========== toString ==========
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "WrapperStrategy{" +
|
||||
"dependWrapperStrategyMapper=" + dependWrapperStrategyMapper +
|
||||
", dependMustStrategyMapper=" + dependMustStrategyMapper +
|
||||
", dependenceStrategy=" + dependenceStrategy +
|
||||
", skipStrategy=" + skipStrategy +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -660,7 +660,7 @@ public abstract class WorkerWrapper<T, V> {
|
||||
|
||||
static final State[] states_of_skipOrAfterWork = new State[]{SKIP, AFTER_WORK};
|
||||
|
||||
static final State[] states_of_checkTimeoutAllowStates = new State[]{INIT, STARTED, WORKING};
|
||||
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};
|
||||
|
||||
@@ -732,6 +732,7 @@ public abstract class WorkerWrapper<T, V> {
|
||||
*
|
||||
* @param excepts 范围。
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
static boolean inStates(AtomicInteger state, State... excepts) {
|
||||
int current;
|
||||
boolean inExcepts;
|
||||
@@ -753,7 +754,7 @@ public abstract class WorkerWrapper<T, V> {
|
||||
/**
|
||||
* CAS的判断是否是某个状态
|
||||
*/
|
||||
static boolean isState(AtomicInteger state, State except) {
|
||||
static boolean isState(AtomicInteger state, @SuppressWarnings("SameParameterValue") State except) {
|
||||
return state.compareAndSet(except.id, except.id);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ 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.wrapper.strategy.depend.DependWrapperActionStrategy;
|
||||
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;
|
||||
|
||||
@@ -112,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;
|
||||
}
|
||||
@@ -156,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();
|
||||
}
|
||||
@@ -164,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();
|
||||
}
|
||||
@@ -204,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);
|
||||
}
|
||||
@@ -215,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();
|
||||
}
|
||||
@@ -229,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();
|
||||
}
|
||||
@@ -1,9 +1,7 @@
|
||||
package com.jd.platform.async.wrapper;
|
||||
|
||||
import com.jd.platform.async.exception.CancelSkippedException;
|
||||
import com.jd.platform.async.executor.PollingCenter;
|
||||
import com.jd.platform.async.util.timer.Timeout;
|
||||
import com.jd.platform.async.util.timer.TimerTask;
|
||||
import com.jd.platform.async.worker.ResultState;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
@@ -11,9 +9,13 @@ 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
|
||||
*/
|
||||
@@ -36,8 +38,23 @@ public class WorkerWrapperGroup {
|
||||
* 当全部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;
|
||||
@@ -64,18 +81,38 @@ public class WorkerWrapperGroup {
|
||||
return forParamUseWrappers;
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步等待这组wrapper执行完成
|
||||
*
|
||||
* @return false代表有wrapper超时了。true代表全部wrapper没有超时。
|
||||
*/
|
||||
public boolean awaitFinish() throws InterruptedException {
|
||||
endCDL.await();
|
||||
return !anyTimeout.get();
|
||||
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 {
|
||||
// 已经完成了
|
||||
@@ -84,11 +121,19 @@ public class WorkerWrapperGroup {
|
||||
}
|
||||
AtomicBoolean hasTimeout = new AtomicBoolean(false);
|
||||
// 记录正在运行中的wrapper里,最近的限时时间。
|
||||
AtomicLong minDaley = new AtomicLong(Long.MAX_VALUE);
|
||||
final AtomicLong minDaley = new AtomicLong(Long.MAX_VALUE);
|
||||
final Collection<WorkerWrapper<?, ?>> values = forParamUseWrappers.values();
|
||||
final Stream<WorkerWrapper<?, ?>> stream = values.size() > 1024 ? values.parallelStream() : values.stream();
|
||||
boolean allFinish = stream
|
||||
// 处理超时
|
||||
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 ;
|
||||
@@ -101,27 +146,39 @@ public class WorkerWrapperGroup {
|
||||
if (time_diff == 0) {
|
||||
return;
|
||||
}
|
||||
// use CAS and SPIN for thread safety in parallelStream .
|
||||
do {
|
||||
long getMinDaley = minDaley.get();
|
||||
if (getMinDaley <= time_diff || minDaley.compareAndSet(getMinDaley, time_diff)) {
|
||||
return;
|
||||
// 需要设置最小时间,但是cas失败,则自旋
|
||||
if (getMinDaley <= time_diff && !minDaley.compareAndSet(getMinDaley, time_diff)) {
|
||||
continue;
|
||||
}
|
||||
return;
|
||||
} while (true);
|
||||
})
|
||||
// 判断是否结束,这里如果还有未结束的wrapper则会提前结束流。
|
||||
.allMatch(wrapper -> wrapper.getState().finished());
|
||||
// 判断是否不需要取消且全部结束
|
||||
// 在不需要取消时,这里如果还有未结束的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
|
||||
if (!allFinish) {
|
||||
else {
|
||||
// 如果有正在WORKING的wrapper,则计算一下限时时间,限时完成后轮询它。
|
||||
if (getMinDaley != Long.MAX_VALUE) {
|
||||
PollingCenter.getInstance().checkGroup(this, getMinDaley);
|
||||
}
|
||||
}
|
||||
if (allFinish) {
|
||||
anyTimeout.set(hasTimeout.get());
|
||||
endCDL.countDown();
|
||||
}
|
||||
}
|
||||
|
||||
// hashCode and equals will called WorkerWrapperGroup.this
|
||||
@@ -142,7 +199,7 @@ public class WorkerWrapperGroup {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof WorkerWrapperGroup.CheckFinishTask)) {
|
||||
if (!(obj instanceof CheckFinishTask)) {
|
||||
return false;
|
||||
}
|
||||
return Objects.equals(WorkerWrapperGroup.this, ((CheckFinishTask) obj).getParent());
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -3,14 +3,14 @@ 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()) {
|
||||
@@ -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();
|
||||
}
|
||||
@@ -1,10 +1,13 @@
|
||||
package com.jd.platform.async.wrapper.strategy.depend;
|
||||
|
||||
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;
|
||||
|
||||
@@ -35,7 +38,7 @@ 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}
|
||||
@@ -135,6 +138,7 @@ public interface DependenceStrategy {
|
||||
case EXCEPTION:
|
||||
resultState = !hasFailed ? workResult.getResultState() : resultState;
|
||||
fastFailException = !hasFailed ? workResult.getEx() : fastFailException;
|
||||
// 跳过不算失败
|
||||
hasFailed = true;
|
||||
break;
|
||||
default:
|
||||
@@ -154,8 +158,10 @@ public interface DependenceStrategy {
|
||||
};
|
||||
|
||||
/**
|
||||
* 如果被依赖的工作中任一失败,则立即失败。否则就开始工作(不论之前的工作有没有开始)。
|
||||
* 如果被依赖的工作中任一失败,则立即失败。
|
||||
* 否则就开始工作(不论之前的工作有没有开始)。
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
DependenceStrategy ALL_DEPENDENCIES_NONE_FAILED = new DependenceStrategy() {
|
||||
@Override
|
||||
public DependenceAction.WithProperty judgeAction(Set<WorkerWrapper<?, ?>> dependWrappers,
|
||||
@@ -166,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:
|
||||
}
|
||||
}
|
||||
@@ -187,6 +193,7 @@ public interface DependenceStrategy {
|
||||
* @param theseWrapper 该方法唯一有效参数。
|
||||
* @return 返回生成的 {@link DependenceAction.WithProperty)
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
static DependenceStrategy theseWrapperAllSuccess(Set<WorkerWrapper<?, ?>> theseWrapper) {
|
||||
return new DependenceStrategy() {
|
||||
private final Set<WorkerWrapper<?, ?>> theseWrappers;
|
||||
@@ -239,6 +246,7 @@ public interface DependenceStrategy {
|
||||
*
|
||||
* @deprecated 不推荐使用must开关
|
||||
*/
|
||||
@SuppressWarnings("DeprecatedIsStillUsed")
|
||||
@Deprecated
|
||||
DependenceStrategy IF_MUST_SET_NOT_EMPTY_ALL_SUCCESS_ELSE_ANY = new DependenceStrategy() {
|
||||
@Override
|
||||
@@ -2,7 +2,7 @@ package com.jd.platform.async.wrapper.strategy.skip;
|
||||
|
||||
import com.jd.platform.async.wrapper.WorkerWrapper;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author create by TcSnZh on 2021/5/6-下午3:02
|
||||
@@ -10,6 +10,7 @@ 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>()
|
||||
37
asyncTool-core/src/test/java/v15/cases/Case0.java
Normal file
37
asyncTool-core/src/test/java/v15/cases/Case0.java
Normal 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
|
||||
*/
|
||||
}
|
||||
}
|
||||
37
asyncTool-core/src/test/java/v15/cases/Case01.java
Normal file
37
asyncTool-core/src/test/java/v15/cases/Case01.java
Normal 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
|
||||
*/
|
||||
}
|
||||
}
|
||||
38
asyncTool-core/src/test/java/v15/cases/Case02.java
Normal file
38
asyncTool-core/src/test/java/v15/cases/Case02.java
Normal 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
|
||||
*/
|
||||
}
|
||||
}
|
||||
@@ -43,8 +43,8 @@ class Case1 {
|
||||
)
|
||||
.build();
|
||||
try {
|
||||
Async.beginWork(1000, a, d);
|
||||
} catch (ExecutionException | InterruptedException e) {
|
||||
Async.work(1000, a, d).awaitFinish();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
/* 输出:
|
||||
72
asyncTool-core/src/test/java/v15/cases/Case10.java
Normal file
72
asyncTool-core/src/test/java/v15/cases/Case10.java
Normal 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为SKIP,workResult.ex为CancelSkippedException,即被取消了。
|
||||
不过有时程序运行慢,导致B被取消了,那么C就不会执行,其状态就为INIT了。
|
||||
*/
|
||||
}
|
||||
}
|
||||
@@ -46,7 +46,7 @@ class Case2 {
|
||||
.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.beginWork(20,wrapper100,wrapper200);
|
||||
Async.work(20,wrapper100,wrapper200).awaitFinish();
|
||||
System.out.println(add.getWorkResult());
|
||||
// 输出WorkResult{result=300, resultState=SUCCESS, ex=null}
|
||||
}
|
||||
@@ -45,7 +45,7 @@ class Case3 {
|
||||
// 这里用线程数较少的线程池做示例,对于ALL_DEPENDENCIES_ANY_SUCCESS“仅需一个”的效果会好一点
|
||||
ExecutorService pool = Executors.newFixedThreadPool(2);
|
||||
try {
|
||||
Async.beginWork(1000, pool, a);
|
||||
Async.work(1000, pool, a).awaitFinish();
|
||||
} finally {
|
||||
pool.shutdown();
|
||||
}
|
||||
@@ -56,6 +56,8 @@ class Case3 {
|
||||
wrapper(id=B2) is working
|
||||
wrapper(id=C2) is working
|
||||
wrapper(id=C1) is working
|
||||
wrapper(id=B4) is working
|
||||
// 我们看到B5被跳过了,没有执行callback
|
||||
*/
|
||||
}
|
||||
}
|
||||
@@ -51,7 +51,7 @@ class Case4 {
|
||||
}
|
||||
ExecutorService pool = Executors.newFixedThreadPool(2);
|
||||
try {
|
||||
Async.beginWork(1000, pool, a);
|
||||
Async.work(1000, pool, a).awaitFinish();
|
||||
} finally {
|
||||
pool.shutdown();
|
||||
}
|
||||
@@ -56,7 +56,7 @@ class Case5 {
|
||||
WorkerWrapper<?, ?> start = builder("start").nextOf(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10).build();
|
||||
ExecutorService pool = Executors.newFixedThreadPool(2);
|
||||
try {
|
||||
Async.beginWork(1000, pool, start);
|
||||
Async.work(1000, pool, start).awaitFinish();
|
||||
} finally {
|
||||
pool.shutdown();
|
||||
}
|
||||
@@ -1,17 +1,13 @@
|
||||
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.DependWrapperActionStrategy;
|
||||
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设置“上克下”策略--简单使用与示例
|
||||
@@ -34,12 +30,14 @@ class Case6 {
|
||||
}
|
||||
|
||||
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()
|
||||
@@ -48,7 +46,7 @@ class Case6 {
|
||||
.specialToNextWrapper(fromWrapper -> DependenceAction.START_WORK.emptyProperty(), b)
|
||||
.wrapper(b)
|
||||
.end().build();
|
||||
Async.beginWork(1000, a);
|
||||
Async.work(1000, a).awaitFinish();
|
||||
System.out.println(a.getWorkResult());
|
||||
System.out.println(b.getWorkResult());
|
||||
/* 输出:
|
||||
@@ -50,7 +50,7 @@ class Case7 {
|
||||
.build(),
|
||||
builder("E", 5).nextOf(d).build()
|
||||
).build();
|
||||
Async.beginWork(1000, a);
|
||||
Async.work(1000, a).awaitFinish();
|
||||
/* 输出:
|
||||
wrapper(id=A) is working
|
||||
wrapper(id=E) is working
|
||||
@@ -55,7 +55,7 @@ class Case8 {
|
||||
.nextOf(builder("C", 20).build())
|
||||
.build())
|
||||
.build();
|
||||
Async.beginWork(15, a);
|
||||
Async.work(20, a).awaitFinish();
|
||||
/* 输出:
|
||||
wrapper(id=A) has begin .
|
||||
wrapper(id=A) is working
|
||||
@@ -67,6 +67,7 @@ class Case8 {
|
||||
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)
|
||||
...
|
||||
以下异常信息省略
|
||||
*/
|
||||
}
|
||||
65
asyncTool-core/src/test/java/v15/cases/Case9.java
Normal file
65
asyncTool-core/src/test/java/v15/cases/Case9.java
Normal 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 : 省略
|
||||
*/
|
||||
}
|
||||
}
|
||||
19
asyncTool-openutil/pom.xml
Normal file
19
asyncTool-openutil/pom.xml
Normal 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>
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 + "}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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() + "]";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.jd.platform.async.util.timer;
|
||||
package com.jd.platform.async.openutil.timer;
|
||||
|
||||
/**
|
||||
* @author create by TcSnZh on 2021/5/12-下午6:36
|
||||
@@ -10,6 +10,7 @@ public abstract class AbstractWheelTimer implements Timer, AutoCloseable {
|
||||
|
||||
public abstract void start();
|
||||
|
||||
@SuppressWarnings("RedundantThrows")
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
stop();
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.jd.platform.async.util.timer;
|
||||
package com.jd.platform.async.openutil.timer;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
@@ -10,12 +10,11 @@ import java.util.concurrent.atomic.AtomicLong;
|
||||
* 从netty里抄来的,删去了一些功能。
|
||||
* <p/>
|
||||
* <b>
|
||||
* 如果违反开源协议,请联系作者: zh0u.he@qq.com
|
||||
* 如果违反开源协议,请联系作者: 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 {
|
||||
|
||||
@@ -42,6 +41,7 @@ public class HashedWheelTimer extends AbstractWheelTimer {
|
||||
* ({@link Executors#defaultThreadFactory()}), default tick duration, and
|
||||
* default number of ticks per wheel.
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public HashedWheelTimer() {
|
||||
this(Executors.defaultThreadFactory());
|
||||
}
|
||||
@@ -56,6 +56,7 @@ public class HashedWheelTimer extends AbstractWheelTimer {
|
||||
* @throws NullPointerException if {@code unit} is {@code null}
|
||||
* @throws IllegalArgumentException if {@code tickDuration} is <= 0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public HashedWheelTimer(long tickDuration, TimeUnit unit) {
|
||||
this(Executors.defaultThreadFactory(), tickDuration, unit);
|
||||
}
|
||||
@@ -70,6 +71,7 @@ public class HashedWheelTimer extends AbstractWheelTimer {
|
||||
* @throws NullPointerException if {@code unit} is {@code null}
|
||||
* @throws IllegalArgumentException if either of {@code tickDuration} and {@code ticksPerWheel} is <= 0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public HashedWheelTimer(long tickDuration, TimeUnit unit, int ticksPerWheel) {
|
||||
this(Executors.defaultThreadFactory(), tickDuration, unit, ticksPerWheel);
|
||||
}
|
||||
@@ -118,28 +120,7 @@ public class HashedWheelTimer extends AbstractWheelTimer {
|
||||
public HashedWheelTimer(
|
||||
ThreadFactory threadFactory,
|
||||
long tickDuration, TimeUnit unit, int ticksPerWheel) {
|
||||
this(threadFactory, tickDuration, unit, ticksPerWheel, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 leakDetection {@code true} if leak detection should be enabled always,
|
||||
* if false it will only be enabled if the worker thread is not
|
||||
* a daemon thread.
|
||||
* @throws NullPointerException if either of {@code threadFactory} and {@code unit} is {@code null}
|
||||
* @throws IllegalArgumentException if either of {@code tickDuration} and {@code ticksPerWheel} is <= 0
|
||||
*/
|
||||
public HashedWheelTimer(
|
||||
ThreadFactory threadFactory,
|
||||
long tickDuration, TimeUnit unit, int ticksPerWheel, boolean leakDetection) {
|
||||
this(threadFactory, tickDuration, unit, ticksPerWheel, leakDetection, -1);
|
||||
this(threadFactory, tickDuration, unit, ticksPerWheel, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -151,21 +132,19 @@ public class HashedWheelTimer extends AbstractWheelTimer {
|
||||
* @param tickDuration the duration between tick
|
||||
* @param unit the time unit of the {@code tickDuration}
|
||||
* @param ticksPerWheel the size of the wheel
|
||||
* @param leakDetection {@code true} if leak detection should be enabled always,
|
||||
* if false it will only be enabled if the worker thread is not
|
||||
* a daemon thread.
|
||||
* @param maxPendingTimeouts The maximum number of pending timeouts after which call to
|
||||
* {@code newTimeout} will result in
|
||||
* {@link java.util.concurrent.RejectedExecutionException}
|
||||
* {@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 <= 0
|
||||
*/
|
||||
public HashedWheelTimer(
|
||||
ThreadFactory threadFactory,
|
||||
long tickDuration, TimeUnit unit, int ticksPerWheel, boolean leakDetection,
|
||||
long maxPendingTimeouts) {
|
||||
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 !");
|
||||
@@ -427,6 +406,7 @@ public class HashedWheelTimer extends AbstractWheelTimer {
|
||||
}
|
||||
|
||||
try {
|
||||
//noinspection BusyWait
|
||||
Thread.sleep(sleepTimeMs);
|
||||
} catch (InterruptedException ignored) {
|
||||
if (workerState.get() == WORKER_STATE_SHUTDOWN) {
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.jd.platform.async.util.timer;
|
||||
package com.jd.platform.async.openutil.timer;
|
||||
|
||||
/**
|
||||
* 借鉴netty。
|
||||
@@ -32,5 +32,6 @@ public interface Timeout {
|
||||
*
|
||||
* @return 如果取消成功完成,则为true,否则为false
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
boolean cancel();
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
package com.jd.platform.async.util.timer;
|
||||
package com.jd.platform.async.openutil.timer;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
@@ -23,6 +24,7 @@ public interface Timer {
|
||||
*/
|
||||
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 -> {
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.jd.platform.async.util.timer;
|
||||
package com.jd.platform.async.openutil.timer;
|
||||
|
||||
/**
|
||||
* 类似于netty的TimerTask。
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
37
asyncTool-openutil/src/test/java/openutiltest/TestGraph.java
Normal file
37
asyncTool-openutil/src/test/java/openutiltest/TestGraph.java
Normal 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();
|
||||
}
|
||||
}
|
||||
7
pom.xml
7
pom.xml
@@ -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>
|
||||
@@ -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);
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package com.jd.platform.async.util.collection;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* 一个反复循环的迭代器
|
||||
*
|
||||
* @author create by TcSnZh on 2021/5/9-下午6:25
|
||||
*/
|
||||
public interface WheelIterator<E> extends Iterator<E> {
|
||||
@Override
|
||||
E next();
|
||||
|
||||
/**
|
||||
* 一轮的元素数
|
||||
*/
|
||||
int cycle();
|
||||
|
||||
@Override
|
||||
default boolean hasNext() {
|
||||
return cycle() > 0;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user