Skip to content

Commit 7dde6a2

Browse files
committed
[docs update]补充几个工作流引擎开源项目
1 parent c800fc0 commit 7dde6a2

File tree

2 files changed

+26
-76
lines changed

2 files changed

+26
-76
lines changed

docs/java/concurrent/java-concurrent-questions-03.md

Lines changed: 19 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -18,90 +18,33 @@ head:
1818

1919
### ThreadLocal 有什么用?
2020

21-
通常情况下,我们创建的变量是可以被任何一个线程访问并修改的。**如果想实现每一个线程都有自己的专属本地变量该如何解决呢**
21+
通常情况下,我们创建的变量可以被任何一个线程访问和修改。这在多线程环境中可能导致数据竞争和线程安全问题。那么,**如果想让每个线程都有自己的专属本地变量,该如何实现呢**
2222

23-
JDK 中自带的`ThreadLocal`类正是为了解决这样的问题。 **`ThreadLocal`类主要解决的就是让每个线程绑定自己的值,可以将`ThreadLocal`类形象的比喻成存放数据的盒子,盒子中可以存储每个线程的私有数据。**
23+
JDK 中提供的 `ThreadLocal` 类正是为了解决这个问题。**`ThreadLocal` 类允许每个线程绑定自己的值**,可以将其形象地比喻为一个“存放数据的盒子”。每个线程都有自己独立的盒子,用于存储私有数据,确保不同线程之间的数据互不干扰。
2424

25-
如果你创建了一个`ThreadLocal`变量,那么访问这个变量的每个线程都会有这个变量的本地副本,这也是`ThreadLocal`变量名的由来。他们可以使用 `get()` `set()` 方法来获取默认值或将其值更改为当前线程所存的副本的值,从而避免了线程安全问题。
25+
当你创建一个 `ThreadLocal` 变量时,每个访问该变量的线程都会拥有一个独立的副本。这也是 `ThreadLocal` 名称的由来。线程可以通过 `get()` 方法获取自己线程的本地副本,或通过 `set()` 方法修改该副本的值,从而避免了线程安全问题。
2626

27-
再举个简单的例子:两个人去宝屋收集宝物,这两个共用一个袋子的话肯定会产生争执,但是给他们两个人每个人分配一个袋子的话就不会出现这样的问题。如果把这两个人比作线程的话,那么 ThreadLocal 就是用来避免这两个线程竞争的。
28-
29-
### 如何使用 ThreadLocal?
30-
31-
相信看了上面的解释,大家已经搞懂 `ThreadLocal` 类是个什么东西了。下面简单演示一下如何在项目中实际使用 `ThreadLocal`
27+
举个简单的例子:假设有两个人去宝屋收集宝物。如果他们共用一个袋子,必然会产生争执;但如果每个人都有一个独立的袋子,就不会有这个问题。如果将这两个人比作线程,那么 `ThreadLocal` 就是用来避免这两个线程竞争同一个资源的方法。
3228

3329
```java
34-
import java.text.SimpleDateFormat;
35-
import java.util.Random;
36-
37-
public class ThreadLocalExample implements Runnable{
38-
39-
// SimpleDateFormat 不是线程安全的,所以每个线程都要有自己独立的副本
40-
private static final ThreadLocal<SimpleDateFormat> formatter = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyyMMdd HHmm"));
41-
42-
public static void main(String[] args) throws InterruptedException {
43-
ThreadLocalExample obj = new ThreadLocalExample();
44-
for(int i=0 ; i<10; i++){
45-
Thread t = new Thread(obj, ""+i);
46-
Thread.sleep(new Random().nextInt(1000));
47-
t.start();
48-
}
49-
}
50-
51-
@Override
52-
public void run() {
53-
System.out.println("Thread Name= "+Thread.currentThread().getName()+" default Formatter = "+formatter.get().toPattern());
54-
try {
55-
Thread.sleep(new Random().nextInt(1000));
56-
} catch (InterruptedException e) {
57-
e.printStackTrace();
58-
}
59-
//formatter pattern is changed here by thread, but it won't reflect to other threads
60-
formatter.set(new SimpleDateFormat());
30+
public class ThreadLocalExample {
31+
private static ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> 0);
6132

62-
System.out.println("Thread Name= "+Thread.currentThread().getName()+" formatter = "+formatter.get().toPattern());
33+
public static void main(String[] args) {
34+
Runnable task = () -> {
35+
int value = threadLocal.get();
36+
value += 1;
37+
threadLocal.set(value);
38+
System.out.println(Thread.currentThread().getName() + " Value: " + threadLocal.get());
39+
};
40+
41+
Thread thread1 = new Thread(task, "Thread-1");
42+
Thread thread2 = new Thread(task, "Thread-2");
43+
44+
thread1.start(); // 输出: Thread-1 Value: 1
45+
thread2.start(); // 输出: Thread-2 Value: 1
6346
}
64-
6547
}
66-
67-
```
68-
69-
输出结果 :
70-
71-
```plain
72-
Thread Name= 0 default Formatter = yyyyMMdd HHmm
73-
Thread Name= 0 formatter = yy-M-d ah:mm
74-
Thread Name= 1 default Formatter = yyyyMMdd HHmm
75-
Thread Name= 2 default Formatter = yyyyMMdd HHmm
76-
Thread Name= 1 formatter = yy-M-d ah:mm
77-
Thread Name= 3 default Formatter = yyyyMMdd HHmm
78-
Thread Name= 2 formatter = yy-M-d ah:mm
79-
Thread Name= 4 default Formatter = yyyyMMdd HHmm
80-
Thread Name= 3 formatter = yy-M-d ah:mm
81-
Thread Name= 4 formatter = yy-M-d ah:mm
82-
Thread Name= 5 default Formatter = yyyyMMdd HHmm
83-
Thread Name= 5 formatter = yy-M-d ah:mm
84-
Thread Name= 6 default Formatter = yyyyMMdd HHmm
85-
Thread Name= 6 formatter = yy-M-d ah:mm
86-
Thread Name= 7 default Formatter = yyyyMMdd HHmm
87-
Thread Name= 7 formatter = yy-M-d ah:mm
88-
Thread Name= 8 default Formatter = yyyyMMdd HHmm
89-
Thread Name= 9 default Formatter = yyyyMMdd HHmm
90-
Thread Name= 8 formatter = yy-M-d ah:mm
91-
Thread Name= 9 formatter = yy-M-d ah:mm
92-
```
93-
94-
从输出中可以看出,虽然 `Thread-0` 已经改变了 `formatter` 的值,但 `Thread-1` 默认格式化值与初始化值相同,其他线程也一样。
95-
96-
上面用于创建 `ThreadLocal` 变量的那段代码用到了 Java8 的知识,它等于下面这段代码,如果你写了下面这段代码的话,IDEA 会提示你转换为 Java8 的格式(IDEA 真的不错!)。因为 ThreadLocal 类在 Java 8 中扩展,使用一个新的方法`withInitial()`,将 Supplier 功能接口作为参数。
97-
98-
```java
99-
private static final ThreadLocal<SimpleDateFormat> formatter = new ThreadLocal<SimpleDateFormat>(){
100-
@Override
101-
protected SimpleDateFormat initialValue(){
102-
return new SimpleDateFormat("yyyyMMdd HHmm");
103-
}
104-
};
10548
```
10649

10750
### ⭐️ThreadLocal 原理了解吗?

docs/open-source-project/system-design.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,13 @@ icon: "xitongsheji"
128128
- [EasyScheduler](https://github.com/analysys/EasyScheduler "EasyScheduler") (已经更名为 DolphinScheduler,已经成为 Apache 孵化器项目):分布式易扩展的可视化工作流任务调度平台,主要解决“复杂任务依赖但无法直接监控任务健康状态”的问题。
129129
- [PowerJob](https://gitee.com/KFCFans/PowerJob):新一代分布式任务调度与计算框架,支持 CRON、API、固定频率、固定延迟等调度策略,提供工作流来编排任务解决依赖关系,使用简单,功能强大,文档齐全,欢迎各位接入使用!<http://www.powerjob.tech/>
130130

131+
## 工作流
132+
133+
1. [Flowable](https://github.com/flowable/flowable-engine) :Activiti5 的一个分支发展而来,功能丰富,在 Activiti 的基础上,引入了更多高级功能,如更强大的 CMMN(案例管理模型与符号)、DMN(决策模型与符号)支持,以及更灵活的集成选项。
134+
2. [Activiti](https://github.com/Activiti/Activiti):功能扩展相对保守,适合需要稳定 BPMN 2.0 工作流引擎的传统企业应用。
135+
3. [Warm-Flow](https://gitee.com/dromara/warm-flow):国产开源工作流引擎,其特点简洁轻量但又不简单,五脏俱全,组件独立,可扩展。
136+
4. [FlowLong](https://gitee.com/aizuda/flowlong):国产开源工作流引擎,专门中国特色流程审批打造。
137+
131138
## 分布式
132139

133140
### API 网关

0 commit comments

Comments
 (0)