> {
+ /**
+ * 有多少行
+ */
+ int lineLength();
+
+ /**
+ * 有多少列
+ */
+ int columnLength();
+
+ /**
+ * 添加元素到指定位置
+ *
+ * @param line 行
+ * @param column 列
+ * @param element 元素
+ * @return 如果之前添加过元素,将返回替换掉的之前的元素
+ * @throws IndexOutOfBoundsException 行列超出范围
+ */
+ E add(int line, int column, E element);
+
+ /**
+ * 如果不存在的话则添加元素
+ *
+ * {@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 fullLine(int line);
+
+ /**
+ * 获取整列的元素
+ *
+ * @param column 列号
+ * @return 返回key为行号,value为元素的Map
+ * @throws IndexOutOfBoundsException 列号超出范围
+ */
+ Map fullColumn(int column);
+
+ /**
+ * 迭代器
+ *
+ * @param foreachOrder 遍历顺序
+ * @return 如果本容器不允许null值存在,只需返回存在的元素的键即可。如果允许null值存在,仅需返回包括人工放入的null值的键即可。
+ */
+ Iterator extends Point> iterator(Comparator foreachOrder);
+
+ @Override
+ default Iterator> iterator() {
+ //noinspection unchecked
+ return (Iterator) iterator(BiInt.cmp_m_asc_n_asc);
+ }
+
+ /**
+ * 流
+ */
+ default Stream extends Point> stream() {
+ return StreamSupport.stream(spliterator(), false);
+ }
+
+ default Stream extends Point> parallelStream() {
+ return StreamSupport.stream(spliterator(), true);
+ }
+
+ default Spliterator> spliterator(Comparator foreachOrder) {
+ return Spliterators.spliteratorUnknownSize(iterator(foreachOrder), 0);
+ }
+
+ default Stream extends Point> stream(Comparator foreachOrder) {
+ return StreamSupport.stream(spliterator(foreachOrder), false);
+ }
+
+ default Stream extends Point> parallelStream(Comparator foreachOrder) {
+ return StreamSupport.stream(spliterator(foreachOrder), true);
+ }
+
+ /**
+ * 端点
+ *
+ * @param 元素泛型
+ */
+ interface Point {
+ BiInt getIdx();
+
+ default int getLine() {
+ return getIdx().getM();
+ }
+
+ default int getColumn() {
+ return getIdx().getN();
+ }
+
+ E getElement();
+ }
+}
diff --git a/asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/collection/BiTree.java b/asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/collection/BiTree.java
new file mode 100644
index 0000000..0ed4d44
--- /dev/null
+++ b/asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/collection/BiTree.java
@@ -0,0 +1,76 @@
+package com.jd.platform.async.openutil.collection;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.function.Function;
+
+/**
+ * 二叉树
+ *
+ * @author create by TcSnZh on 2021/5/15-下午8:00
+ */
+public interface BiTree extends Tree {
+ // todo
+
+ /**
+ * 二叉树节点
+ */
+ interface BiNode extends Node {
+ @Override
+ default BiNode getParent() {
+ throw new UnsupportedOperationException("Get parent node is not supported.");
+ }
+
+ BiNode getLeft();
+
+ BiNode getRight();
+
+ @Override
+ default Collection extends BiNode> getChildren() {
+ return Arrays.asList(getLeft(), getRight());
+ }
+ }
+
+ /**
+ * 返回一个通俗易懂的字符画。
+ *
+ * 从leetcode上抄的。若有侵权请联系 {@code zh0u.he@qq.com},将会删除。
+ *
+ * @param node 根节点
+ * @param provideName 节点显示在图中的名字。
+ * @param 根节点泛型
+ * @return 返回一个字符画
+ */
+ static String toPrettyString(N node, Function provideName) {
+ StringBuilder sb = new StringBuilder();
+ //noinspection unchecked
+ _toPrettyString(node, "", true, sb, (Function) provideName);
+ return sb.toString();
+ }
+
+ /**
+ * jdk8没有private static,只能加条下划线意思意思了。
+ */
+ static void _toPrettyString(N node,
+ String prefix,
+ boolean isLeft,
+ StringBuilder sb,
+ Function provideName) {
+ if (node == null) {
+ sb.append("(Empty tree)");
+ return;
+ }
+
+ BiNode right = node.getRight();
+ if (right != null) {
+ _toPrettyString(right, prefix + (isLeft ? "│ " : " "), false, sb, provideName);
+ }
+
+ sb.append(prefix).append(isLeft ? "└── " : "┌── ").append(provideName.apply(node)).append('\n');
+
+ BiNode left = node.getLeft();
+ if (left != null) {
+ _toPrettyString(left, prefix + (isLeft ? " " : "│ "), true, sb, provideName);
+ }
+ }
+}
diff --git a/asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/collection/CachedStoreArk.java b/asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/collection/CachedStoreArk.java
new file mode 100644
index 0000000..a8a1362
--- /dev/null
+++ b/asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/collection/CachedStoreArk.java
@@ -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 extends AbstractStoreArk {
+ private final StoreArk inner;
+
+ private final Map cacheMap = new HashMap<>();
+
+ public CachedStoreArk() {
+ this(CommonStoreArk::new);
+ }
+
+ private CachedStoreArk(Supplier> 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> iterator() {
+ return inner.iterator();
+ }
+
+ @Override
+ public int findId(E element) {
+ Integer idNullable = cacheMap.get(element);
+ return idNullable == null ? -1 : idNullable;
+ }
+}
diff --git a/asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/collection/CollisionRangeTable.java b/asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/collection/CollisionRangeTable.java
new file mode 100644
index 0000000..f5e72dd
--- /dev/null
+++ b/asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/collection/CollisionRangeTable.java
@@ -0,0 +1,10 @@
+package com.jd.platform.async.openutil.collection;
+
+/**
+ * 冲突范围表
+ *
+ * @author create by TcSnZh on 2021/5/16-上午1:36
+ */
+public class CollisionRangeTable {
+ // todo
+}
diff --git a/asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/collection/CommonDirectedGraph.java b/asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/collection/CommonDirectedGraph.java
new file mode 100644
index 0000000..0683d2c
--- /dev/null
+++ b/asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/collection/CommonDirectedGraph.java
@@ -0,0 +1,145 @@
+package com.jd.platform.async.openutil.collection;
+
+import java.util.*;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * 线程不安全的有向图。
+ *
+ * 不允许放入null。
+ *
+ * @author create by TcSnZh on 2021/5/14-上午2:22
+ */
+public class CommonDirectedGraph extends AbstractDirectedGraph {
+
+ // ========== properties ==========
+
+ private final StoreArk nodes = new CachedStoreArk<>();
+ private final Array2D 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> removeNode(N node) {
+ int id = findNodeId(Objects.requireNonNull(node), true);
+ LinkedHashSet> 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> getRelationFrom(N from) {
+ int id = findNodeId(Objects.requireNonNull(from), true);
+ LinkedHashSet> 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> getRelationTo(N to) {
+ int id = findNodeId(Objects.requireNonNull(to), true);
+ LinkedHashSet> 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 nodesView() {
+ return new AbstractNodesView() {
+ @Override
+ public Iterator iterator() {
+ return nodes.stream().map(Map.Entry::getValue).iterator();
+ }
+
+ @Override
+ public int size() {
+ return nodes.size();
+ }
+ };
+ }
+
+ @Override
+ public Set extends Entry> getRelations() {
+ return arr.stream().map((Function, Entry>) 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 extends AbstractEntry {
+ 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;
+ }
+ }
+}
diff --git a/asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/collection/CommonStoreArk.java b/asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/collection/CommonStoreArk.java
new file mode 100644
index 0000000..ae05f6f
--- /dev/null
+++ b/asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/collection/CommonStoreArk.java
@@ -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 extends AbstractStoreArk {
+ private Object[] elements;
+
+ /**
+ * 已经分配的下标数
+ */
+ private int allocSize = 0;
+
+ /**
+ * 保存着最小空元素的队列
+ */
+ private final Queue 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> iterator() {
+ return new Iterator>() {
+ private final Map.Entry[] items;
+
+ private int idx = 0;
+
+ {
+ //noinspection unchecked
+ items = new Map.Entry[size()];
+ int itemsIdx = 0;
+ Iterator 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() {
+ 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 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;
+ }
+}
diff --git a/asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/collection/DirectedGraph.java b/asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/collection/DirectedGraph.java
new file mode 100644
index 0000000..4f326d2
--- /dev/null
+++ b/asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/collection/DirectedGraph.java
@@ -0,0 +1,185 @@
+package com.jd.platform.async.openutil.collection;
+
+import java.util.AbstractSet;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * @author create by TcSnZh on 2021/5/16-下午11:27
+ */
+public interface DirectedGraph extends Graph {
+ @Override
+ default boolean isDirected() {
+ return true;
+ }
+
+ static DirectedGraph readOnlyDigraph(DirectedGraph source) {
+ return new ReadOnlyDirectedGraph<>(source);
+ }
+
+ static DirectedGraph synchronizedDigraph(DirectedGraph source) {
+ return synchronizedDigraph(source, new Object());
+ }
+
+ static DirectedGraph synchronizedDigraph(DirectedGraph source, Object mutex) {
+ return new SyncDirectedGraph<>(source, mutex);
+ }
+
+ class ReadOnlyDirectedGraph extends AbstractDirectedGraph {
+ private final DirectedGraph source;
+
+ public ReadOnlyDirectedGraph(DirectedGraph 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> removeNode(N node) {
+ throw readOnlyGraph();
+ }
+
+ @Override
+ public R putRelation(N fromNode, R relation, N toNode) {
+ throw readOnlyGraph();
+ }
+
+ @Override
+ public Set extends Entry> getRelationFrom(N from) {
+ return source.getRelationFrom(from);
+ }
+
+ @Override
+ public Set extends Entry> getRelationTo(N to) {
+ return source.getRelationTo(to);
+ }
+
+ @Override
+ public Set nodesView() {
+ return new AbstractSet() {
+ private final Set nodesViewSource = source.nodesView();
+
+ @Override
+ public Iterator iterator() {
+ return new Iterator() {
+ private final Iterator 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> getRelations() {
+ return source.getRelations();
+ }
+ }
+
+ class SyncDirectedGraph extends AbstractDirectedGraph {
+ private final DirectedGraph source;
+ private final Object mutex;
+
+ public SyncDirectedGraph(DirectedGraph 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> 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> getRelationFrom(N from) {
+ synchronized (mutex) {
+ return source.getRelationFrom(from);
+ }
+ }
+
+ @Override
+ public Set extends Entry> getRelationTo(N to) {
+ synchronized (mutex) {
+ return source.getRelationTo(to);
+ }
+ }
+
+ @Override
+ public Set nodesView() {
+ synchronized (mutex) {
+ return Collections.synchronizedSet(source.nodesView());
+ }
+ }
+
+ @Override
+ public Set extends Entry> getRelations() {
+ synchronized (mutex) {
+ return source.getRelations();
+ }
+ }
+ }
+}
diff --git a/asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/collection/Graph.java b/asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/collection/Graph.java
new file mode 100644
index 0000000..e9903ff
--- /dev/null
+++ b/asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/collection/Graph.java
@@ -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 {
+ /**
+ * 添加节点。
+ * 如果节点已经存在,则不会添加。
+ *
+ * @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> 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> getRelationFrom(N from);
+
+ /**
+ * 获取“以这个节点为目标”的所有关系
+ *
+ * @param to 被关系的节点
+ * @return 返回 {@link Entry}键。
+ */
+ Set extends Entry> getRelationTo(N to);
+
+ /**
+ * 返回全部节点视图
+ *
+ * @return 视图
+ */
+ Set nodesView();
+
+ /**
+ * 返回全部关系,返回的是新Set
+ *
+ * @return 与本类无关的Set
+ */
+ Set extends Entry> getRelations();
+
+ /**
+ * 是否有向
+ */
+ boolean isDirected();
+
+ interface Entry {
+ N getFrom();
+
+ N getTo();
+
+ R getRelation();
+ }
+}
diff --git a/asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/collection/SparseArray2D.java b/asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/collection/SparseArray2D.java
new file mode 100644
index 0000000..39dee10
--- /dev/null
+++ b/asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/collection/SparseArray2D.java
@@ -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;
+
+/**
+ * 稀疏二维数组。
+ *
+ * 可以设置是否允许存入null。
+ *
+ * @author create by TcSnZh on 2021/5/14-下午9:45
+ */
+public class SparseArray2D extends AbstractArray2D {
+
+ // ========== properties ==========
+
+ /**
+ * 限制长宽,默认为Integer.MAX_VALUE。稀疏数组不在乎这些。
+ */
+ private final int maxLineLength;
+ private final int maxColumnLength;
+ private final boolean allowNull;
+
+ private final Map items = new HashMap<>();
+
+ // ========== index cache properties ==========
+
+ /**
+ * 缓存行列索引
+ */
+ private final NavigableMap> indexOfLine2columns = new TreeMap<>(Integer::compareTo);
+ private final NavigableMap> 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 还是 没有存入过
+ *
+ * {@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 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 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> iterator(Comparator foreachOrder) {
+ return new Iterator>() {
+ private final Iterator> it;
+ private Point 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 next() {
+ Map.Entry 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 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 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);
+ }
+ }
+ }
+}
diff --git a/asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/collection/StoreArk.java b/asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/collection/StoreArk.java
new file mode 100644
index 0000000..063413c
--- /dev/null
+++ b/asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/collection/StoreArk.java
@@ -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中最小的。
+ *
+ * 类似于我们去游泳馆,里面的存放个人物品的柜子。
+ * 放进去元素后,会分配一个id。然后凭借该id取出元素。
+ * 不过不同于这些现实中的柜子的是,这个存储柜必定会提供最小的id,并且必定>0。
+ *
+ *
+ * @author create by TcSnZh on 2021/5/14-上午2:29
+ */
+public interface StoreArk extends Iterable> {
+ /**
+ * 存入元素
+ *
+ * @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> stream() {
+ return StreamSupport.stream(spliterator(), false);
+ }
+}
diff --git a/asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/collection/Tree.java b/asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/collection/Tree.java
new file mode 100644
index 0000000..b3d6ec3
--- /dev/null
+++ b/asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/collection/Tree.java
@@ -0,0 +1,16 @@
+package com.jd.platform.async.openutil.collection;
+
+import java.util.Collection;
+
+/**
+ * @author create by TcSnZh on 2021/5/15-下午7:58
+ */
+public interface Tree {
+ interface Node {
+ default Node getParent(){
+ throw new UnsupportedOperationException("Get parent node is not supported.");
+ }
+
+ Collection extends Node> getChildren();
+ }
+}
diff --git a/src/main/java/com/jd/platform/async/util/collection/WheelIterator.java b/asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/collection/WheelIterator.java
similarity index 87%
rename from src/main/java/com/jd/platform/async/util/collection/WheelIterator.java
rename to asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/collection/WheelIterator.java
index 97ea47d..0c9ad40 100644
--- a/src/main/java/com/jd/platform/async/util/collection/WheelIterator.java
+++ b/asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/collection/WheelIterator.java
@@ -1,4 +1,4 @@
-package com.jd.platform.async.util.collection;
+package com.jd.platform.async.openutil.collection;
import java.util.Iterator;
diff --git a/asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/concurrent/RangeLock.java b/asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/concurrent/RangeLock.java
new file mode 100644
index 0000000..2d92fe2
--- /dev/null
+++ b/asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/concurrent/RangeLock.java
@@ -0,0 +1,46 @@
+package com.jd.platform.async.openutil.concurrent;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+
+/**
+ * 范围锁 todo
+ *
+ * @author create by TcSnZh on 2021/5/15-下午6:23
+ */
+public interface RangeLock extends Lock {
+ void lock(int start, int end);
+
+ boolean tryLock(int start, int end);
+
+ boolean tryLock(int start, int end, long time, TimeUnit unit) throws InterruptedException;
+
+ void lockInterruptibly(int start, int end) throws InterruptedException;
+
+ @Override
+ Condition newCondition();
+
+ @Override
+ void unlock();
+
+ @Override
+ default void lock() {
+ lock(Integer.MIN_VALUE, Integer.MAX_VALUE);
+ }
+
+ @Override
+ default void lockInterruptibly() throws InterruptedException {
+ lockInterruptibly(Integer.MIN_VALUE, Integer.MAX_VALUE);
+ }
+
+ @Override
+ default boolean tryLock() {
+ return tryLock(Integer.MIN_VALUE, Integer.MAX_VALUE);
+ }
+
+ @Override
+ default boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
+ return tryLock(Integer.MIN_VALUE, Integer.MAX_VALUE, time, unit);
+ }
+}
diff --git a/src/main/java/com/jd/platform/async/util/timer/AbstractWheelTimer.java b/asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/timer/AbstractWheelTimer.java
similarity index 82%
rename from src/main/java/com/jd/platform/async/util/timer/AbstractWheelTimer.java
rename to asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/timer/AbstractWheelTimer.java
index cc2d711..d26fa1e 100644
--- a/src/main/java/com/jd/platform/async/util/timer/AbstractWheelTimer.java
+++ b/asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/timer/AbstractWheelTimer.java
@@ -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();
diff --git a/src/main/java/com/jd/platform/async/util/timer/HashedWheelTimer.java b/asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/timer/HashedWheelTimer.java
similarity index 93%
rename from src/main/java/com/jd/platform/async/util/timer/HashedWheelTimer.java
rename to asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/timer/HashedWheelTimer.java
index 864e9cd..90df6e9 100644
--- a/src/main/java/com/jd/platform/async/util/timer/HashedWheelTimer.java
+++ b/asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/timer/HashedWheelTimer.java
@@ -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里抄来的,删去了一些功能。
*
*
- * 如果违反开源协议,请联系作者: zh0u.he@qq.com
+ * 如果违反开源协议,请联系作者: zh.jobs@foxmail.com
* If violate the open source agreement, please contact the author : zh0u.he@qq.com
*
*
* @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) {
diff --git a/src/main/java/com/jd/platform/async/util/timer/Timeout.java b/asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/timer/Timeout.java
similarity index 91%
rename from src/main/java/com/jd/platform/async/util/timer/Timeout.java
rename to asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/timer/Timeout.java
index 1bbc9b1..84e875c 100644
--- a/src/main/java/com/jd/platform/async/util/timer/Timeout.java
+++ b/asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/timer/Timeout.java
@@ -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();
}
diff --git a/src/main/java/com/jd/platform/async/util/timer/Timer.java b/asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/timer/Timer.java
similarity index 87%
rename from src/main/java/com/jd/platform/async/util/timer/Timer.java
rename to asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/timer/Timer.java
index 3ab2052..17870c1 100644
--- a/src/main/java/com/jd/platform/async/util/timer/Timer.java
+++ b/asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/timer/Timer.java
@@ -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 timeoutRef = new AtomicReference<>();
newTimeout(timeout -> {
diff --git a/src/main/java/com/jd/platform/async/util/timer/TimerTask.java b/asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/timer/TimerTask.java
similarity index 79%
rename from src/main/java/com/jd/platform/async/util/timer/TimerTask.java
rename to asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/timer/TimerTask.java
index 6ea3c76..047590c 100644
--- a/src/main/java/com/jd/platform/async/util/timer/TimerTask.java
+++ b/asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/timer/TimerTask.java
@@ -1,4 +1,4 @@
-package com.jd.platform.async.util.timer;
+package com.jd.platform.async.openutil.timer;
/**
* 类似于netty的TimerTask。
diff --git a/asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/unsafe/UnsafeUtil.java b/asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/unsafe/UnsafeUtil.java
new file mode 100644
index 0000000..35ecf2a
--- /dev/null
+++ b/asyncTool-openutil/src/main/java/com/jd/platform/async/openutil/unsafe/UnsafeUtil.java
@@ -0,0 +1,33 @@
+package com.jd.platform.async.openutil.unsafe;
+
+import sun.misc.Unsafe;
+
+import java.lang.reflect.Field;
+
+/**
+ * @author create by TcSnZh on 2021/5/16-下午4:36
+ */
+@SuppressWarnings({"AlibabaAbstractClassShouldStartWithAbstractNaming", "unused"})
+abstract class UnsafeUtil {
+ private static final Unsafe unsafe;
+
+ static {
+ Field theUnsafe;
+ try {
+ theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
+ } catch (NoSuchFieldException e) {
+ throw new Error(e);
+ }
+ theUnsafe.setAccessible(true);
+ try {
+ unsafe = (Unsafe) theUnsafe.get(null);
+ } catch (IllegalAccessException e) {
+ throw new Error(e);
+ }
+ }
+
+ @SuppressWarnings("FinalStaticMethod")
+ public static final Unsafe getUnsafe() {
+ return unsafe;
+ }
+}
diff --git a/asyncTool-openutil/src/test/java/openutiltest/PrintProxy.java b/asyncTool-openutil/src/test/java/openutiltest/PrintProxy.java
new file mode 100644
index 0000000..c212ad3
--- /dev/null
+++ b/asyncTool-openutil/src/test/java/openutiltest/PrintProxy.java
@@ -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 {
+ public PrintProxy(Class 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();
+ }
+
+}
diff --git a/asyncTool-openutil/src/test/java/openutiltest/TestGraph.java b/asyncTool-openutil/src/test/java/openutiltest/TestGraph.java
new file mode 100644
index 0000000..533485b
--- /dev/null
+++ b/asyncTool-openutil/src/test/java/openutiltest/TestGraph.java
@@ -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
+ */
+public class TestGraph {
+ public static void main(String[] args) {
+ test_CommonDirectedGraph();
+ }
+
+ private static void test_CommonDirectedGraph() {
+ System.out.println("\n\n ==================== 测试正常使用 ==================");
+ //noinspection unchecked
+ DirectedGraph 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();
+ }
+}
diff --git a/asyncTool-scheduling/pom.xml b/asyncTool-scheduling/pom.xml
new file mode 100644
index 0000000..7561f8d
--- /dev/null
+++ b/asyncTool-scheduling/pom.xml
@@ -0,0 +1,31 @@
+
+
+
+ asyncTool
+ com.jd.platform
+ 1.5.0-SNAPSHOT
+
+ 4.0.0
+
+ asyncTool-scheduling
+
+
+ 8
+ 8
+
+
+
+
+ asyncTool-core
+ com.jd.platform
+ 1.5.0-SNAPSHOT
+
+
+ com.alibaba
+ fastjson
+ 1.2.76
+
+
+
\ No newline at end of file
diff --git a/asyncTool-scheduling/src/main/java/com/jd/platform/async/scheduling/DefaultSchedulingJsonParser.java b/asyncTool-scheduling/src/main/java/com/jd/platform/async/scheduling/DefaultSchedulingJsonParser.java
new file mode 100644
index 0000000..47cbbc6
--- /dev/null
+++ b/asyncTool-scheduling/src/main/java/com/jd/platform/async/scheduling/DefaultSchedulingJsonParser.java
@@ -0,0 +1,40 @@
+package com.jd.platform.async.scheduling;
+
+import com.jd.platform.async.scheduling.model.SchedulingDrawingsModel;
+
+/**
+ * @author create by TcSnZh on 2021/5/17-上午1:22
+ */
+public class DefaultSchedulingJsonParser implements SchedulingJsonParser {
+
+
+ // ========== singleton instance ==========
+
+ /**
+ * 私有构造方法,需要通过{@link #getInstance()}方法获取单例。
+ */
+ private DefaultSchedulingJsonParser() {
+ }
+
+ /**
+ * 获取单例
+ */
+ public static DefaultSchedulingJsonParser getInstance() {
+ return instance;
+ }
+
+ private static final DefaultSchedulingJsonParser instance = new DefaultSchedulingJsonParser();
+
+ // ========== public methods ==========
+
+ @Override
+ public SchedulingDrawingsModel parse(String json) {
+
+
+
+ // todo
+ return null;
+ }
+
+ // ========== util methods ==========
+}
diff --git a/asyncTool-scheduling/src/main/java/com/jd/platform/async/scheduling/SchedulingFactory.java b/asyncTool-scheduling/src/main/java/com/jd/platform/async/scheduling/SchedulingFactory.java
new file mode 100644
index 0000000..49c7c7d
--- /dev/null
+++ b/asyncTool-scheduling/src/main/java/com/jd/platform/async/scheduling/SchedulingFactory.java
@@ -0,0 +1,35 @@
+package com.jd.platform.async.scheduling;
+
+import sun.misc.Unsafe;
+
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.Function;
+
+/**
+ * 调度工厂。传入图纸生成一组wrapper。
+ *
+ * @author create by TcSnZh on 2021/5/17-上午1:11
+ */
+public class SchedulingFactory {
+ private final String factoryName;
+
+ /**
+ * 无参构造,默认使用 {@code 栈信息<自增long值> } 作为工厂名
+ */
+ public SchedulingFactory() {
+ this(Thread.currentThread().getStackTrace()[2] + "<" + defaultFactoryNameCount.getAndIncrement() + ">");
+ }
+
+ /**
+ * 指定工厂名
+ *
+ * @param factoryName 工厂名
+ */
+ public SchedulingFactory(String factoryName) {
+ this.factoryName = factoryName;
+ }
+
+ // ========== static ==========
+
+ private static final AtomicLong defaultFactoryNameCount = new AtomicLong();
+}
diff --git a/asyncTool-scheduling/src/main/java/com/jd/platform/async/scheduling/SchedulingJsonParser.java b/asyncTool-scheduling/src/main/java/com/jd/platform/async/scheduling/SchedulingJsonParser.java
new file mode 100644
index 0000000..ee4b908
--- /dev/null
+++ b/asyncTool-scheduling/src/main/java/com/jd/platform/async/scheduling/SchedulingJsonParser.java
@@ -0,0 +1,24 @@
+package com.jd.platform.async.scheduling;
+
+import com.jd.platform.async.scheduling.model.SchedulingDrawingsModel;
+
+/**
+ * @author create by TcSnZh on 2021/5/17-下午7:22
+ */
+public interface SchedulingJsonParser {
+
+ /**
+ * 解析json为图纸对象
+ *
+ * @param json json
+ * @return 返回图纸对象接口
+ */
+ SchedulingDrawingsModel parse(String json);
+
+ /**
+ * 默认实现
+ */
+ static SchedulingJsonParser getDefaultInstance() {
+ return DefaultSchedulingJsonParser.getInstance();
+ }
+}
diff --git a/asyncTool-scheduling/src/main/java/com/jd/platform/async/scheduling/exception/IllegalConfigException.java b/asyncTool-scheduling/src/main/java/com/jd/platform/async/scheduling/exception/IllegalConfigException.java
new file mode 100644
index 0000000..21b55e6
--- /dev/null
+++ b/asyncTool-scheduling/src/main/java/com/jd/platform/async/scheduling/exception/IllegalConfigException.java
@@ -0,0 +1,25 @@
+package com.jd.platform.async.scheduling.exception;
+
+/**
+ * @author tcsnzh[zh.jobs@foxmail.com] create this in 2021/5/19-下午7:20
+ */
+public class IllegalConfigException extends Exception{
+ public IllegalConfigException() {
+ }
+
+ public IllegalConfigException(String message) {
+ super(message);
+ }
+
+ public IllegalConfigException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public IllegalConfigException(Throwable cause) {
+ super(cause);
+ }
+
+ public IllegalConfigException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
+ super(message, cause, enableSuppression, writableStackTrace);
+ }
+}
diff --git a/asyncTool-scheduling/src/main/java/com/jd/platform/async/scheduling/model/ObjectModel.java b/asyncTool-scheduling/src/main/java/com/jd/platform/async/scheduling/model/ObjectModel.java
new file mode 100644
index 0000000..6171899
--- /dev/null
+++ b/asyncTool-scheduling/src/main/java/com/jd/platform/async/scheduling/model/ObjectModel.java
@@ -0,0 +1,80 @@
+package com.jd.platform.async.scheduling.model;
+
+import com.jd.platform.async.callback.ICallback;
+import com.jd.platform.async.wrapper.strategy.depend.DependOnUpWrapperStrategy;
+import com.jd.platform.async.wrapper.strategy.depend.DependenceStrategy;
+import com.jd.platform.async.wrapper.strategy.skip.SkipStrategy;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author tcsnzh[zh.jobs@foxmail.com] create this in 2021/5/19-下午7:51
+ */
+@SuppressWarnings("unused")
+public class ObjectModel {
+ protected String constObjectName;
+ protected String className;
+ protected Long sameObjectId;
+ protected Map properties;
+
+ public ObjectModel() {
+ }
+
+ public String getConstObjectName() {
+ return constObjectName;
+ }
+
+ public void setConstObjectName(String constObjectName) {
+ this.constObjectName = constObjectName;
+ }
+
+ public String getClassName() {
+ return className;
+ }
+
+ public void setClassName(String className) {
+ this.className = className;
+ }
+
+ public Long getSameObjectId() {
+ return sameObjectId;
+ }
+
+ public void setSameObjectId(Long sameObjectId) {
+ this.sameObjectId = sameObjectId;
+ }
+
+ public Map getProperties() {
+ return properties;
+ }
+
+ public void setProperties(Map properties) {
+ this.properties = properties;
+ }
+
+ public static Map getConstObjects() {
+ return constObjects;
+ }
+
+ // static constants
+
+ private static final Map constObjects;
+
+ static {
+ constObjects = new HashMap<>(16);
+ constObjects.put("NOT_SKIP", SkipStrategy.NOT_SKIP);
+ constObjects.put("CHECK_ONE_LEVEL", SkipStrategy.CHECK_ONE_LEVEL);
+ constObjects.put("ALL_DEPENDENCIES_ALL_SUCCESS", DependenceStrategy.ALL_DEPENDENCIES_ALL_SUCCESS);
+ constObjects.put("ALL_DEPENDENCIES_ANY_SUCCESS", DependenceStrategy.ALL_DEPENDENCIES_ANY_SUCCESS);
+ constObjects.put("ALL_DEPENDENCIES_NONE_FAILED", DependenceStrategy.ALL_DEPENDENCIES_NONE_FAILED);
+ constObjects.put("SUCCESS_CONTINUE", DependOnUpWrapperStrategy.SUCCESS_CONTINUE);
+ constObjects.put("SUCCESS_START_INIT_CONTINUE", DependOnUpWrapperStrategy.SUCCESS_START_INIT_CONTINUE);
+ constObjects.put("PRINT_EXCEPTION_STACK_TRACE", ICallback.PRINT_EXCEPTION_STACK_TRACE);
+ }
+
+ public static T getConstObject(String name) {
+ //noinspection unchecked
+ return (T) constObjects.get(name);
+ }
+}
diff --git a/asyncTool-scheduling/src/main/java/com/jd/platform/async/scheduling/model/SchedulingDrawingsModel.java b/asyncTool-scheduling/src/main/java/com/jd/platform/async/scheduling/model/SchedulingDrawingsModel.java
new file mode 100644
index 0000000..1e00e68
--- /dev/null
+++ b/asyncTool-scheduling/src/main/java/com/jd/platform/async/scheduling/model/SchedulingDrawingsModel.java
@@ -0,0 +1,255 @@
+package com.jd.platform.async.scheduling.model;
+
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 工厂图纸模型对象。
+ * 具体参数含义,请查阅 QuickStart.md
+ *
+ * @author create by TcSnZh on 2021/5/17-上午1:16
+ */
+@SuppressWarnings("unused")
+public class SchedulingDrawingsModel {
+ protected String drawingsName;
+ protected List wrappers;
+ protected List relations;
+ protected BeginWorkModel beginWork;
+
+ public static class WrapperModel {
+ protected String id;
+ protected ParamModel param;
+ protected ObjectModel worker;
+ protected ObjectModel callback;
+ protected WrapperStrategyModel wrapperStrategy;
+ protected Boolean allowInterrupt;
+ protected Boolean enableTimeout;
+ protected Long timeoutLength;
+ protected TimeUnit timeUnit;
+ protected String extendConfig;
+
+ public static class ParamModel {
+ protected Boolean useObjectModel;
+ protected Object value; // true - ObjectModel ; false - the json converted to type, such as Map\List\String...
+
+ public Boolean getUseObjectModel() {
+ return useObjectModel;
+ }
+
+ public void setUseObjectModel(Boolean useObjectModel) {
+ this.useObjectModel = useObjectModel;
+ }
+
+ public Object getValue() {
+ return value;
+ }
+
+ public void setValue(Object value) {
+ this.value = value;
+ }
+ }
+
+ public static class WrapperStrategyModel {
+ protected Map dependOnUpWrapperStrategyMapper;
+ protected ObjectModel dependenceStrategy;
+ protected ObjectModel skipStrategy;
+
+ public Map getDependOnUpWrapperStrategyMapper() {
+ return dependOnUpWrapperStrategyMapper;
+ }
+
+ public void setDependOnUpWrapperStrategyMapper(Map dependOnUpWrapperStrategyMapper) {
+ this.dependOnUpWrapperStrategyMapper = dependOnUpWrapperStrategyMapper;
+ }
+
+ public ObjectModel getDependenceStrategy() {
+ return dependenceStrategy;
+ }
+
+ public void setDependenceStrategy(ObjectModel dependenceStrategy) {
+ this.dependenceStrategy = dependenceStrategy;
+ }
+
+ public ObjectModel getSkipStrategy() {
+ return skipStrategy;
+ }
+
+ public void setSkipStrategy(ObjectModel skipStrategy) {
+ this.skipStrategy = skipStrategy;
+ }
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public ParamModel getParam() {
+ return param;
+ }
+
+ public void setParam(ParamModel param) {
+ this.param = param;
+ }
+
+ public ObjectModel getWorker() {
+ return worker;
+ }
+
+ public void setWorker(ObjectModel worker) {
+ this.worker = worker;
+ }
+
+ public ObjectModel getCallback() {
+ return callback;
+ }
+
+ public void setCallback(ObjectModel callback) {
+ this.callback = callback;
+ }
+
+ public WrapperStrategyModel getWrapperStrategy() {
+ return wrapperStrategy;
+ }
+
+ public void setWrapperStrategy(WrapperStrategyModel wrapperStrategy) {
+ this.wrapperStrategy = wrapperStrategy;
+ }
+
+ public Boolean getAllowInterrupt() {
+ return allowInterrupt;
+ }
+
+ public void setAllowInterrupt(Boolean allowInterrupt) {
+ this.allowInterrupt = allowInterrupt;
+ }
+
+ public Boolean getEnableTimeout() {
+ return enableTimeout;
+ }
+
+ public void setEnableTimeout(Boolean enableTimeout) {
+ this.enableTimeout = enableTimeout;
+ }
+
+ public Long getTimeoutLength() {
+ return timeoutLength;
+ }
+
+ public void setTimeoutLength(Long timeoutLength) {
+ this.timeoutLength = timeoutLength;
+ }
+
+ public TimeUnit getTimeUnit() {
+ return timeUnit;
+ }
+
+ public void setTimeUnit(TimeUnit timeUnit) {
+ this.timeUnit = timeUnit;
+ }
+
+ public String getExtendConfig() {
+ return extendConfig;
+ }
+
+ public void setExtendConfig(String extendConfig) {
+ this.extendConfig = extendConfig;
+ }
+ }
+
+ public static class RelationModel {
+ protected Object from; // from和to最多有一个数组,剩下的都是String
+ protected Object to;
+
+ public Object getFrom() {
+ return from;
+ }
+
+ public void setFrom(Object from) {
+ this.from = from;
+ }
+
+ public Object getTo() {
+ return to;
+ }
+
+ public void setTo(Object to) {
+ this.to = to;
+ }
+ }
+
+ public static class BeginWorkModel {
+ protected Long timeoutLength;
+ protected TimeUnit timeoutUnit;
+ protected List wrappers;
+ protected String executor;
+
+ public Long getTimeoutLength() {
+ return timeoutLength;
+ }
+
+ public void setTimeoutLength(Long timeoutLength) {
+ this.timeoutLength = timeoutLength;
+ }
+
+ public TimeUnit getTimeoutUnit() {
+ return timeoutUnit;
+ }
+
+ public void setTimeoutUnit(TimeUnit timeoutUnit) {
+ this.timeoutUnit = timeoutUnit;
+ }
+
+ public List getWrappers() {
+ return wrappers;
+ }
+
+ public void setWrappers(List