MCPcopy Index your code
hub / github.com/alibaba/transmittable-thread-local

github.com/alibaba/transmittable-thread-local @v2.14.5

Chat with this repo
repository ↗ · DeepWiki ↗ · release v2.14.5 ↗ · + Follow
322 symbols 802 edges 45 files 149 documented · 46% 5 cross-repo links updated 18d agov2.14.5 · 2023-12-25★ 8,29126 open issues
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

📌 TransmittableThreadLocal(TTL)

Fast CI Strong CI Coverage Status JDK support License Javadocs Maven Central GitHub release GitHub Stars GitHub Forks user repos GitHub issues GitHub Contributors GitHub repo size gitpod: Ready to Code

📖 English Documentation | 📖 中文文档



🔧 Functions

👉 TransmittableThreadLocal(TTL): The missing Java™ std lib(simple & 0-dependency) for framework/middleware, provide an enhanced InheritableThreadLocal that transmits values between threads even using thread pooling components. Support Java 6~21.

Class InheritableThreadLocal in JDK can transmit value to child thread from parent thread.

But when use thread pool, thread is cached up and used repeatedly. Transmitting value from parent thread to child thread has no meaning. Application need transmit value from the time task is created to the time task is executed.

If you have problem or question, please submit Issue or play fork and pull request dance.

From TTL v2.13+ upgrade to Java 8.
If you need Java 6 support, use version 2.12.x Maven Central

🎨 Requirements

The Requirements listed below is also why I sort out TransmittableThreadLocal in my work.

  • Application container or high layer framework transmit information to low layer sdk.
  • Transmit context to logging without application code aware.

👥 User Guide

1. Simple usage

TransmittableThreadLocal<String> context = new TransmittableThreadLocal<>();

// =====================================================

// set in parent thread
context.set("value-set-in-parent");

// =====================================================

// read in child thread, value is "value-set-in-parent"
String value = context.get();

# See the executable demo SimpleDemo.kt with full source code.

This is the function of class InheritableThreadLocal, should use class InheritableThreadLocal instead.

But when use thread pool, thread is cached up and used repeatedly. Transmitting value from parent thread to child thread has no meaning. Application need transmit value from the time task is created to the point task is executed.

The solution is below usage.

2. Transmit value even using thread pool

2.1 Decorate Runnable and Callable

Decorate input Runnable and Callable by TtlRunnable and TtlCallable.

Sample code:

TransmittableThreadLocal<String> context = new TransmittableThreadLocal<>();

// =====================================================

// set in parent thread
context.set("value-set-in-parent");

Runnable task = new RunnableTask();
// extra work, create decorated ttlRunnable object
Runnable ttlRunnable = TtlRunnable.get(task);
executorService.submit(ttlRunnable);

// =====================================================

// read in task, value is "value-set-in-parent"
String value = context.get();

NOTE
Even when the same Runnable task is submitted to the thread pool multiple times, the decoration operations(ie: TtlRunnable.get(task)) is required for each submission to capture the value of the TransmittableThreadLocal context at submission time; That is, if the same task is submitted next time without reperforming decoration and still using the last TtlRunnable, the submitted task will run in the context of the last captured context. The sample code is as follows:

// first submission
Runnable task = new RunnableTask();
executorService.submit(TtlRunnable.get(task));

// ... some biz logic,
// and modified TransmittableThreadLocal context ...
context.set("value-modified-in-parent");

// next submission
// reperform decoration to transmit the modified TransmittableThreadLocal context
executorService.submit(TtlRunnable.get(task));

Above code show how to dealing with Runnable, Callable is similar:

TransmittableThreadLocal<String> context = new TransmittableThreadLocal<>();

// =====================================================

// set in parent thread
context.set("value-set-in-parent");

Callable call = new CallableTask();
// extra work, create decorated ttlCallable object
Callable ttlCallable = TtlCallable.get(call);
executorService.submit(ttlCallable);

// =====================================================

// read in call, value is "value-set-in-parent"
String value = context.get();

# See the executable demo 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 be completed in the thread pool.

Use util class TtlExecutors to decorate thread pool.

Util class TtlExecutors has below methods:

  • getTtlExecutor: decorate interface Executor
  • getTtlExecutorService: decorate interface ExecutorService
  • getTtlScheduledExecutorService: decorate interface ScheduledExecutorService

Sample code:

ExecutorService executorService = ...
// extra work, create decorated executorService object
executorService = TtlExecutors.getTtlExecutorService(executorService);

TransmittableThreadLocal<String> context = new TransmittableThreadLocal<>();

// =====================================================

// set in parent thread
context.set("value-set-in-parent");

Runnable task = new RunnableTask();
Callable call = new CallableTask();
executorService.submit(task);
executorService.submit(call);

// =====================================================

// read in Task or Callable, value is "value-set-in-parent"
String value = context.get();

# See the executable demo TtlExecutorWrapperDemo.kt with full source code.

2.3 Use Java Agent to decorate thread pool implementation class

In this usage, transmittance is transparent(no decoration operation).

Sample code:

// ## 1. upper layer logic of framework ##
TransmittableThreadLocal<String> context = new TransmittableThreadLocal<>();
context.set("value-set-in-parent");

// ## 2. biz logic ##
ExecutorService executorService = Executors.newFixedThreadPool(3);

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 = context.get();

# See the executable demo AgentDemo.kt with full source code, run demo by the script scripts/run-agent-demo.sh.

At present, TTL agent has decorated below JDK execution components(aka. thread pool) implementation:

  • java.util.concurrent.ThreadPoolExecutor and java.util.concurrent.ScheduledThreadPoolExecutor
  • java.util.concurrent.ForkJoinTask(corresponding execution component is java.util.concurrent.ForkJoinPool
    • decoration implementation code is in TtlForkJoinTransformlet.java, supports since version 2.5.1.
    • NOTE: CompletableFuture and (parallel) Stream introduced in Java 8 is executed through ForkJoinPool underneath, so after supporting ForkJoinPool, TTL also supports CompletableFuture and Stream transparently. 🎉
  • java.util.TimerTask(corresponding execution component is java.util.Timer
    • decoration implementation code is in TtlTimerTaskTransformlet.java, supports since version 2.7.0.
    • NOTE: Since version 2.11.2 decoration for TimerTask default is enable (because correctness is first concern, not the best practice like "It is not recommended to use TimerTask" :); before version 2.11.1 default is disable.
    • enabled/disable by agent argument ttl.agent.enable.timer.task:
      • -javaagent:path/to/transmittable-thread-local-2.x.y.jar=ttl.agent.enable.timer.task:true
      • -javaagent:path/to/transmittable-thread-local-2.x.y.jar=ttl.agent.enable.timer.task:false
    • more info about TTL agent arguments, see the javadoc of TtlAgent.java.

Add start options on Java command:

  • -javaagent:path/to/transmittable-thread-local-2.x.y.jar

Java command example:

```bash java -javaagent:transmittable-thread-local-2.x.y.jar \ -cp classes \ com.alibaba.demo.ttl.agent.

Extension points exported contracts — how you extend this code

TtlEnhanced (Interface)
@see com.alibaba.ttl.spi.TtlAttachments @deprecated Use com.alibaba.ttl.spi.TtlEnhanced instead. [10 implementers]
src/main/java/com/alibaba/ttl/TtlEnhanced.java
TtlAttachments (Interface)
The TTL attachments for TTL tasks, eg: com.alibaba.ttl.TtlRunnable, com.alibaba.ttl.TtlCallable. @autho [6 implementers]
src/main/java/com/alibaba/ttl/spi/TtlAttachments.java
TtlWrapper (Interface)
Ttl Wrapper interface. Used to mark wrapper types, for example: com.alibaba.ttl.TtlCallable</li [17 implementers]
src/main/java/com/alibaba/ttl/spi/TtlWrapper.java
DisableInheritableThreadFactory (Interface)
Disable inheritable ThreadFactory. @author Jerry Lee (oldratlee at gmail dot com) @see ThreadFactory @since 2.1 [18 implementers]
src/main/java/com/alibaba/ttl/threadpool/DisableInheritableThreadFactory.java
DisableInheritableForkJoinWorkerThreadFactory (Interface)
Disable inheritable ForkJoinWorkerThreadFactory. @author Jerry Lee (oldratlee at gmail dot com) @since 2.10.1 [18 implementers]
src/main/java/com/alibaba/ttl/threadpool/DisableInheritableForkJoinWorkerThreadFactory.java

Core symbols most depended-on inside this repo

get
called by 18
src/main/java/com/alibaba/ttl/TransmittableThreadLocal.java
info
called by 18
src/main/java/com/alibaba/ttl/threadpool/agent/internal/logging/Logger.java
equals
called by 15
src/main/java/com/alibaba/ttl/threadpool/ExecutorTtlWrapper.java
get
called by 14
src/main/java/com/alibaba/ttl/TtlCallable.java
restore
called by 13
src/main/java/com/alibaba/ttl/TransmittableThreadLocal.java
capture
called by 12
src/main/java/com/alibaba/ttl/TransmittableThreadLocal.java
replay
called by 11
src/main/java/com/alibaba/ttl/TransmittableThreadLocal.java
newHashMap
called by 9
src/main/java/com/alibaba/ttl/TransmittableThreadLocal.java

Shape

Method 269
Class 44
Interface 9

Languages

Java100%

Modules by API surface

src/main/java/com/alibaba/ttl/TransmittableThreadLocal.java47 symbols
src/main/java/com/alibaba/ttl/TtlWrappers.java43 symbols
src/main/java/com/alibaba/ttl/threadpool/agent/internal/transformlet/impl/Utils.java13 symbols
src/main/java/com/alibaba/ttl/threadpool/agent/internal/logging/Logger.java13 symbols
src/main/java/com/alibaba/ttl/threadpool/TtlExecutors.java13 symbols
src/main/java/com/alibaba/ttl/TtlRunnable.java13 symbols
src/main/java/com/alibaba/ttl/TtlCallable.java13 symbols
src/main/java/com/alibaba/ttl/threadpool/ExecutorServiceTtlWrapper.java11 symbols
src/main/java/com/alibaba/ttl/TtlTimerTask.java11 symbols
src/test/java/com/alibaba/demo/ttl/CustomizedBlockingQueueWithTtlDemo.java9 symbols
src/main/java/com/alibaba/ttl/threadpool/agent/TtlAgent.java9 symbols
src/main/java/com/alibaba/ttl/threadpool/agent/internal/transformlet/impl/TtlPriorityBlockingQueueTransformlet.java7 symbols

Dependencies from manifests, versioned

com.github.spotbugs:spotbugs-annotations
com.google.code.findbugs:jsr305
io.github.microutils:kotlin-logging-jvm3.0.5 · 1×
io.kotest:kotest-assertions-core-jvm
io.kotest:kotest-property-jvm
io.kotest:kotest-runner-junit4-jvm
io.kotest:kotest-runner-junit5-jvm
io.mockk:mockk-jvm1.13.7 · 1×
io.reactivex.rxjava2:rxkotlin2.4.0 · 1×
org.apache.commons:commons-lang33.14.0 · 1×
org.codehaus.mojo:extra-enforcer-rules1.7.0 · 1×

For agents

$ claude mcp add transmittable-thread-local \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact