提交 6a43fb90 编写于 作者: oldratlee's avatar oldratlee 🔥

add the executable demo for different usage

上级 97bdccd2
......@@ -5,8 +5,8 @@
[![Coverage Status](https://img.shields.io/codecov/c/github/alibaba/transmittable-thread-local/master.svg)](https://codecov.io/gh/alibaba/transmittable-thread-local/branch/master)
[![Maintainability](https://api.codeclimate.com/v1/badges/de6af6136e538cf1557c/maintainability)](https://codeclimate.com/github/alibaba/transmittable-thread-local/maintainability)
[![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html)
[![Javadocs](https://img.shields.io/github/release/alibaba/transmittable-thread-local.svg?label=javadoc&color=3D9970)](https://alibaba.github.io/transmittable-thread-local/apidocs/)
[![Maven Central](https://img.shields.io/maven-central/v/com.alibaba/transmittable-thread-local.svg?color=6B5B95)](https://search.maven.org/search?q=g:com.alibaba%20AND%20a:transmittable-thread-local&core=gav)
[![Javadocs](https://img.shields.io/github/release/alibaba/transmittable-thread-local.svg?label=javadoc&color=3d7c47)](https://alibaba.github.io/transmittable-thread-local/apidocs/)
[![Maven Central](https://img.shields.io/maven-central/v/com.alibaba/transmittable-thread-local.svg?color=2d545e)](https://search.maven.org/search?q=g:com.alibaba%20AND%20a:transmittable-thread-local&core=gav)
[![GitHub release](https://img.shields.io/github/release/alibaba/transmittable-thread-local.svg)](https://github.com/alibaba/transmittable-thread-local/releases)
[![Chat at gitter.im](https://badges.gitter.im/alibaba/transmittable-thread-local.svg)](https://gitter.im/alibaba/transmittable-thread-local?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![GitHub Stars](https://img.shields.io/github/stars/alibaba/transmittable-thread-local)](https://github.com/alibaba/transmittable-thread-local/stargazers)
......@@ -68,15 +68,17 @@ The Requirements listed below is also why I sort out `TTL` in my work.
```java
// set in parent thread
TransmittableThreadLocal<String> parent = new TransmittableThreadLocal<String>();
parent.set("value-set-in-parent");
TransmittableThreadLocal<String> ttlContext = new TransmittableThreadLocal<String>();
ttlContext.set("value-set-in-parent");
// =====================================================
// read in child thread, value is "value-set-in-parent"
String value = parent.get();
String value = ttlContext.get();
```
\# See the executable demo [`SimpleDemo.kt`](src/test/java/com/alibaba/demo/ttl/SimpleDemo.kt) with full source code.
This is the function of class [`InheritableThreadLocal`](https://docs.oracle.com/javase/10/docs/api/java/lang/InheritableThreadLocal.html), should use class [`InheritableThreadLocal`](https://docs.oracle.com/javase/10/docs/api/java/lang/InheritableThreadLocal.html) instead.
But when use thread pool, thread is cached up and used repeatedly. Transmitting value from parent thread to child thread has no meaning.
......@@ -97,7 +99,7 @@ Sample code:
TransmittableThreadLocal<String> parent = new TransmittableThreadLocal<String>();
parent.set("value-set-in-parent");
Runnable task = new Task("1");
Runnable task = new RunnableTask();
// extra work, create decorated ttlRunnable object
Runnable ttlRunnable = TtlRunnable.get(task);
executorService.submit(ttlRunnable);
......@@ -114,7 +116,7 @@ above code show how to dealing with `Runnable`, `Callable` is similar:
TransmittableThreadLocal<String> parent = new TransmittableThreadLocal<String>();
parent.set("value-set-in-parent");
Callable call = new Call("1");
Callable call = new CallableTask();
// extra work, create decorated ttlCallable object
Callable ttlCallable = TtlCallable.get(call);
executorService.submit(ttlCallable);
......@@ -125,6 +127,8 @@ executorService.submit(ttlCallable);
String value = parent.get();
```
\# See the executable demo [`TtlWrapperDemo.kt`](src/test/java/com/alibaba/demo/ttl/TtlWrapperDemo.kt) with full source code.
### 2.2 Decorate thread pool
Eliminating the work of `Runnable` and `Callable` Decoration every time it is submitted to thread pool. This work can completed in the thread pool.
......@@ -149,8 +153,8 @@ executorService = TtlExecutors.getTtlExecutorService(executorService);
TransmittableThreadLocal<String> parent = new TransmittableThreadLocal<String>();
parent.set("value-set-in-parent");
Runnable task = new Task("1");
Callable call = new Call("2");
Runnable task = new RunnableTask();
Callable call = new CallableTask();
executorService.submit(task);
executorService.submit(call);
......@@ -160,6 +164,8 @@ executorService.submit(call);
String value = parent.get();
```
\# See the executable demo [`TtlExecutorWrapperDemo.kt`](src/test/java/com/alibaba/demo/ttl/TtlExecutorWrapperDemo.kt) with full source code.
### 2.3 Use Java Agent to decorate thread pool implementation class
In this usage, transmission is transparent\(no decoration operation\).
......@@ -167,20 +173,24 @@ In this usage, transmission is transparent\(no decoration operation\).
Sample code:
```java
// ## 1. upper layer logic of framework ##
TransmittableThreadLocal<String> context = new TransmittableThreadLocal<String>();
context.set("value-set-in-parent");
// ## 2. biz logic ##
ExecutorService executorService = Executors.newFixedThreadPool(3);
Runnable task = new Task("1");
Callable call = new Call("2");
Runnable task = new RunnableTask();
Callable call = new CallableTask();
executorService.submit(task);
executorService.submit(call);
// =====================================================
// ## 3. underlayer logic of framework ##
// read in Task or Callable, value is "value-set-in-parent"
String value = parent.get();
String value = context.get();
```
See demo [`AgentDemo.kt`](src/test/java/com/alibaba/demo/agent/AgentDemo.kt).
\# See the executable demo [`AgentDemo.kt`](src/test/java/com/alibaba/demo/ttl/agent/AgentDemo.kt) with full source code, run demo by the script [`scripts/run-agent-demo.sh`](scripts/run-agent-demo.sh).
At present, `TTL` agent has decorated below `JDK` execution components(aka. thread pool) implementation:
......@@ -226,7 +236,7 @@ Java command example:
```bash
java -javaagent:transmittable-thread-local-2.x.x.jar \
-cp classes \
com.alibaba.ttl.threadpool.agent.demo.AgentDemo
com.alibaba.demo.ttl.agent.AgentDemo
```
or
......@@ -237,7 +247,7 @@ or
java -javaagent:path/to/ttl-foo-name-changed.jar \
-Xbootclasspath/a:path/to/ttl-foo-name-changed.jar \
-cp classes \
com.alibaba.ttl.threadpool.agent.demo.AgentDemo
com.alibaba.demo.ttl.agent.AgentDemo
```
Run the script [`scripts/run-agent-demo.sh`](scripts/run-agent-demo.sh)
......
......@@ -5,8 +5,8 @@
[![Coverage Status](https://img.shields.io/codecov/c/github/alibaba/transmittable-thread-local/master.svg)](https://codecov.io/gh/alibaba/transmittable-thread-local/branch/master)
[![Maintainability](https://api.codeclimate.com/v1/badges/de6af6136e538cf1557c/maintainability)](https://codeclimate.com/github/alibaba/transmittable-thread-local/maintainability)
[![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html)
[![Javadocs](https://img.shields.io/github/release/alibaba/transmittable-thread-local.svg?label=javadoc&color=3D9970)](https://alibaba.github.io/transmittable-thread-local/apidocs/)
[![Maven Central](https://img.shields.io/maven-central/v/com.alibaba/transmittable-thread-local.svg?color=6B5B95)](https://search.maven.org/search?q=g:com.alibaba%20AND%20a:transmittable-thread-local&core=gav)
[![Javadocs](https://img.shields.io/github/release/alibaba/transmittable-thread-local.svg?label=javadoc&color=3d7c47)](https://alibaba.github.io/transmittable-thread-local/apidocs/)
[![Maven Central](https://img.shields.io/maven-central/v/com.alibaba/transmittable-thread-local.svg?color=2d545e)](https://search.maven.org/search?q=g:com.alibaba%20AND%20a:transmittable-thread-local&core=gav)
[![GitHub release](https://img.shields.io/github/release/alibaba/transmittable-thread-local.svg)](https://github.com/alibaba/transmittable-thread-local/releases)
[![Chat at gitter.im](https://badges.gitter.im/alibaba/transmittable-thread-local.svg)](https://gitter.im/alibaba/transmittable-thread-local?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![GitHub Stars](https://img.shields.io/github/stars/alibaba/transmittable-thread-local)](https://github.com/alibaba/transmittable-thread-local/stargazers)
......@@ -97,15 +97,17 @@
```java
// 在父线程中设置
TransmittableThreadLocal<String> parent = new TransmittableThreadLocal<String>();
parent.set("value-set-in-parent");
TransmittableThreadLocal<String> ttlContext = new TransmittableThreadLocal<String>();
ttlContext.set("value-set-in-parent");
// =====================================================
// 在子线程中可以读取,值是"value-set-in-parent"
String value = parent.get();
String value = ttlContext.get();
```
\# 完整可运行的Demo代码参见[`SimpleDemo.kt`](src/test/java/com/alibaba/demo/ttl/SimpleDemo.kt)
这是其实是[`InheritableThreadLocal`](https://docs.oracle.com/javase/10/docs/api/java/lang/InheritableThreadLocal.html)的功能,应该使用[`InheritableThreadLocal`](https://docs.oracle.com/javase/10/docs/api/java/lang/InheritableThreadLocal.html)来完成。
但对于使用线程池等会池化复用线程的执行组件的情况,线程由线程池创建好,并且线程是池化起来反复使用的;这时父子线程关系的`ThreadLocal`值传递已经没有意义,应用需要的实际上是把 **任务提交给线程池时**`ThreadLocal`值传递到 **任务执行时**
......@@ -121,10 +123,10 @@ String value = parent.get();
示例代码:
```java
TransmittableThreadLocal<String> parent = new TransmittableThreadLocal<String>();
parent.set("value-set-in-parent");
TransmittableThreadLocal<String> ttlContext = new TransmittableThreadLocal<String>();
ttlContext.set("value-set-in-parent");
Runnable task = new Task("1");
Runnable task = new RunnableTask();
// 额外的处理,生成修饰了的对象ttlRunnable
Runnable ttlRunnable = TtlRunnable.get(task);
executorService.submit(ttlRunnable);
......@@ -132,16 +134,16 @@ executorService.submit(ttlRunnable);
// =====================================================
// Task中可以读取,值是"value-set-in-parent"
String value = parent.get();
String value = ttlContext.get();
```
上面演示了`Runnable``Callable`的处理类似
```java
TransmittableThreadLocal<String> parent = new TransmittableThreadLocal<String>();
parent.set("value-set-in-parent");
TransmittableThreadLocal<String> ttlContext = new TransmittableThreadLocal<String>();
ttlContext.set("value-set-in-parent");
Callable call = new Call("1");
Callable call = new CallableTask();
// 额外的处理,生成修饰了的对象ttlCallable
Callable ttlCallable = TtlCallable.get(call);
executorService.submit(ttlCallable);
......@@ -149,9 +151,11 @@ executorService.submit(ttlCallable);
// =====================================================
// Call中可以读取,值是"value-set-in-parent"
String value = parent.get();
String value = ttlContext.get();
```
\# 完整可运行的Demo代码参见[`TtlWrapperDemo.kt`](src/test/java/com/alibaba/demo/ttl/TtlWrapperDemo.kt)
#### 整个过程的完整时序图
![时序图](docs/TransmittableThreadLocal-sequence-diagram.png)
......@@ -173,20 +177,22 @@ ExecutorService executorService = ...
// 额外的处理,生成修饰了的对象executorService
executorService = TtlExecutors.getTtlExecutorService(executorService);
TransmittableThreadLocal<String> parent = new TransmittableThreadLocal<String>();
parent.set("value-set-in-parent");
TransmittableThreadLocal<String> ttlContext = new TransmittableThreadLocal<String>();
ttlContext.set("value-set-in-parent");
Runnable task = new Task("1");
Callable call = new Call("2");
Runnable task = new RunnableTask();
Callable call = new CallableTask();
executorService.submit(task);
executorService.submit(call);
// =====================================================
// Task或是Call中可以读取,值是"value-set-in-parent"
String value = parent.get();
String value = ttlContext.get();
```
\# 完整可运行的Demo代码参见[`TtlExecutorWrapperDemo.kt`](src/test/java/com/alibaba/demo/ttl/TtlExecutorWrapperDemo.kt)
### 2.3 使用`Java Agent`来修饰`JDK`线程池实现类
这种方式,实现线程池的传递是透明的,业务代码中没有修饰`Runnable`或是线程池的代码。即可以做到应用代码 **无侵入**
......@@ -202,8 +208,8 @@ context.set("value-set-in-parent");
// ## 2. 应用逻辑,后续流程业务调用框架下层逻辑 ##
ExecutorService executorService = Executors.newFixedThreadPool(3);
Runnable task = new Task("1");
Callable call = new Call("2");
Runnable task = new RunnableTask();
Callable call = new CallableTask();
executorService.submit(task);
executorService.submit(call);
......@@ -212,7 +218,7 @@ executorService.submit(call);
String value = context.get();
```
Demo参见[`AgentDemo.kt`](src/test/java/com/alibaba/demo/agent/AgentDemo.kt)。执行工程下的脚本[`scripts/run-agent-demo.sh`](scripts/run-agent-demo.sh)即可运行Demo。
Demo参见[`AgentDemo.kt`](src/test/java/com/alibaba/demo/ttl/agent/AgentDemo.kt)。执行工程下的脚本[`scripts/run-agent-demo.sh`](scripts/run-agent-demo.sh)即可运行Demo。
目前`TTL Agent`中,修饰了的`JDK`执行器组件(即如线程池)如下:
......@@ -270,7 +276,7 @@ Demo参见[`AgentDemo.kt`](src/test/java/com/alibaba/demo/agent/AgentDemo.kt)。
```bash
java -javaagent:path/to/transmittable-thread-local-2.x.x.jar \
-cp classes \
com.alibaba.ttl.threadpool.agent.demo.AgentDemo
com.alibaba.demo.ttl.agent.AgentDemo
```
或是
......@@ -281,7 +287,7 @@ java -javaagent:path/to/transmittable-thread-local-2.x.x.jar \
java -javaagent:path/to/ttl-foo-name-changed.jar \
-Xbootclasspath/a:path/to/ttl-foo-name-changed.jar \
-cp classes \
com.alibaba.ttl.threadpool.agent.demo.AgentDemo
com.alibaba.demo.ttl.agent.AgentDemo
```
# 🔌 Java API Docs
......
......@@ -124,7 +124,7 @@ String result = runSupplierWithCaptured(captured, () -> {
这样可以减少`Java`启动命令行上的`Agent`的配置。
在自己的`Agent`中加上`TTL Agent`的逻辑,示例代码如下([`YourXxxAgent.java`](../src/test/java/com/alibaba/demo/agent/YourXxxAgent.java)):
在自己的`Agent`中加上`TTL Agent`的逻辑,示例代码如下([`YourXxxAgent.java`](../src/test/java/com/alibaba/demo/ttl/agent/YourXxxAgent.java)):
```java
import com.alibaba.ttl.threadpool.agent.TtlAgent;
......
......@@ -5,4 +5,4 @@ source ./common.sh
runCmd "${JAVA_CMD[@]}" -cp "$(getClasspathWithoutTtlJar)" \
"-javaagent:$(getTtlJarPath)=ttl.agent.logger:STDOUT" \
com.alibaba.demo.agent.AgentDemo
com.alibaba.demo.ttl.agent.AgentDemo
package com.alibaba.demo.ttl
import com.alibaba.ttl.TransmittableThreadLocal
import kotlin.concurrent.thread
/**
* @author Jerry Lee (oldratlee at gmail dot com)
*/
fun main() {
val ttlContext = TransmittableThreadLocal<String>()
ttlContext.set("value-set-in-parent")
println("[parent thread] set ${ttlContext.get()}")
/////////////////////////////////////
// create sub-thread
/////////////////////////////////////
thread {
val value = ttlContext.get()
println("[child thread] get $value")
}.join()
println("[parent thread] get ${ttlContext.get()}")
}
package com.alibaba.demo.ttl
import com.alibaba.ttl.TransmittableThreadLocal
import com.alibaba.ttl.threadpool.TtlExecutors
import java.util.concurrent.Callable
import java.util.concurrent.Executors
/**
* @author Jerry Lee (oldratlee at gmail dot com)
*/
fun main() {
val ttlExecutorService = Executors.newCachedThreadPool().let {
// return TTL wrapper from normal ExecutorService
TtlExecutors.getTtlExecutorService(it)
}!!
val ttlContext = TransmittableThreadLocal<String>()
ttlContext.set("value-set-in-parent")
println("[parent thread] set ${ttlContext.get()}")
/////////////////////////////////////
// Runnable
/////////////////////////////////////
val task = Runnable { println("[child thread] get ${ttlContext.get()} in Runnable") }
ttlExecutorService.submit(task).get()
/////////////////////////////////////
// Callable
/////////////////////////////////////
val call = Callable {
println("[child thread] get ${ttlContext.get()} in Callable")
42
}
ttlExecutorService.submit(call).get()
/////////////////////////////////////
// cleanup
/////////////////////////////////////
ttlExecutorService.shutdown()
}
package com.alibaba.demo.ttl
import com.alibaba.ttl.TransmittableThreadLocal
import com.alibaba.ttl.TtlCallable
import com.alibaba.ttl.TtlRunnable
import java.util.concurrent.Callable
import java.util.concurrent.Executors
/**
* @author Jerry Lee (oldratlee at gmail dot com)
*/
fun main() {
val executorService = Executors.newCachedThreadPool()
val ttlContext = TransmittableThreadLocal<String>()
ttlContext.set("value-set-in-parent")
println("[parent thread] set ${ttlContext.get()}")
/////////////////////////////////////
// Runnable / TtlRunnable
/////////////////////////////////////
val task = Runnable { println("[child thread] get ${ttlContext.get()} in Runnable") }
val ttlRunnable = TtlRunnable.get(task)!!
executorService.submit(ttlRunnable).get()
/////////////////////////////////////
// Callable / TtlCallable
/////////////////////////////////////
val call = Callable {
println("[child thread] get ${ttlContext.get()} in Callable")
42
}
val ttlCallable = TtlCallable.get(call)!!
executorService.submit(ttlCallable).get()
/////////////////////////////////////
// cleanup
/////////////////////////////////////
executorService.shutdown()
}
@file:JvmName("AgentDemo")
package com.alibaba.demo.agent
package com.alibaba.demo.ttl.agent
import com.alibaba.ttl.TransmittableThreadLocal
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
/**
* @author Jerry Lee (oldratlee at gmail dot com)
......@@ -32,9 +31,6 @@ fun main() {
printTtlInstancesInfo("Main - After execution of thread pool")
executorService.shutdown()
if (!executorService.awaitTermination(3, TimeUnit.SECONDS)) {
throw IllegalStateException("Fail to shutdown executorService!")
}
}
private data class Person(var name: String = "unnamed", var age: Int = -1)
......
package com.alibaba.demo.agent;
package com.alibaba.demo.ttl.agent;
import com.alibaba.ttl.threadpool.agent.TtlAgent;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册