Giter Club home page Giter Club logo

transmittable-thread-local's Introduction

Transmittable ThreadLocal(TTL)

Build Status Coverage Status Maven Central GitHub release
Join the chat at https://gitter.im/alibaba/transmittable-thread-local GitHub issues Dependency Status License

🔧 功能

👉 在使用线程池等会缓存线程的组件情况下,提供ThreadLocal值的传递功能。

JDKInheritableThreadLocal类可以完成父子线程值的传递。 但对于使用线程池等会缓存线程的组件的情况,线程由线程池创建好,并且线程是缓存起来反复使用的;这时父子线程关系的上下文传递已经没有意义,应用中要做上下文传递,实际上是在把 任务提交给线程池时的上下文传递到 任务执行时

本库提供的TransmittableThreadLocal类继承并加强InheritableThreadLocal类,解决上述的问题,使用详见User Guide

欢迎 👏

🎨 需求场景

ThreadLocal的需求场景即是TTL的潜在需求场景,如果你的业务需要『在使用线程池等会缓存线程的组件情况下传递ThreadLocal』则是TTL目标场景。

下面是几个典型场景例子。

  1. 分布式跟踪系统
  2. 应用容器或上层框架跨应用代码给下层SDK传递信息
  3. 日志收集记录系统上下文

各个场景的展开说明参见子文档 需求场景

👥 User Guide

使用类TransmittableThreadLocal来保存上下文,并跨线程池传递。

TransmittableThreadLocal继承InheritableThreadLocal,使用方式也类似。

InheritableThreadLocal,添加了protected方法copy,用于定制 任务提交给线程池时的上下文传递到 任务执行时时的拷贝行为,缺省是传递的是引用。

具体使用方式见下面的说明。

  1. 简单使用

父线程给子线程传递值。

示例代码:

// 在父线程中设置
TransmittableThreadLocal<String> parent = new TransmittableThreadLocal<String>();
parent.set("value-set-in-parent");

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

// 在子线程中可以读取, 值是"value-set-in-parent"
String value = parent.get(); 

这是其实是InheritableThreadLocal的功能,应该使用InheritableThreadLocal来完成。

但对于使用了异步执行(往往使用线程池完成)的情况,线程由线程池创建好,并且线程是缓存起来反复使用的。

这时父子线程关系的上下文传递已经没有意义,应用中要做上下文传递,实际上是在把 任务提交给线程池时的上下文传递到 任务执行时。 解决方法参见下面的这几种用法。

  1. 保证线程池中传递值

2.1 修饰RunnableCallable

使用com.alibaba.ttl.TtlRunnablecom.alibaba.ttl.TtlCallable来修饰传入线程池的RunnableCallable

示例代码:

TransmittableThreadLocal<String> parent = new TransmittableThreadLocal<String>();
parent.set("value-set-in-parent");

Runnable task = new Task("1");
// 额外的处理,生成修饰了的对象ttlRunnable
Runnable ttlRunnable = TtlRunnable.get(task); 
executorService.submit(ttlRunnable);

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

// Task中可以读取, 值是"value-set-in-parent"
String value = parent.get(); 

上面演示了RunnableCallable的处理类似

TransmittableThreadLocal<String> parent = new TransmittableThreadLocal<String>();
parent.set("value-set-in-parent");

Callable call = new Call("1");
// 额外的处理,生成修饰了的对象ttlCallable
Callable ttlCallable = TtlCallable.get(call);
executorService.submit(ttlCallable);

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

// Call中可以读取, 值是"value-set-in-parent"
String value = parent.get();

整个过程的完整时序图

时序图

2.2 修饰线程池

省去每次RunnableCallable传入线程池时的修饰,这个逻辑可以在线程池中完成。

通过工具类com.alibaba.ttl.threadpool.TtlExecutors完成,有下面的方法:

  • getTtlExecutor:修饰接口Executor
  • getTtlExecutorService:修饰接口ExecutorService
  • ScheduledExecutorService:修饰接口ScheduledExecutorService

示例代码:

ExecutorService executorService = ...
// 额外的处理,生成修饰了的对象executorService
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");
executorService.submit(task);
executorService.submit(call);

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

// Task或是Call中可以读取, 值是"value-set-in-parent"
String value = parent.get(); 

2.3 使用Java Agent来修饰JDK线程池实现类

这种方式,实现线程池的传递是透明的,代码中没有修饰Runnable或是线程池的代码。
# 即可以做到应用代码 无侵入,后面文档有结合实际场景的架构对这一点的说明。

示例代码:

// 框架代码
TransmittableThreadLocal<String> parent = new TransmittableThreadLocal<String>();
parent.set("value-set-in-parent");

// 应用代码
ExecutorService executorService = Executors.newFixedThreadPool(3);

Runnable task = new Task("1");
Callable call = new Call("2");
executorService.submit(task);
executorService.submit(call);

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

// Task或是Call中可以读取, 值是"value-set-in-parent"
String value = parent.get();

Demo参见AgentDemo.java

目前Agent中,修饰了jdk中的两个线程池实现类(实现代码在TtlTransformer.java):

  • java.util.concurrent.ThreadPoolExecutor
  • java.util.concurrent.ScheduledThreadPoolExecutor

Java的启动参数加上:

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

注意

  • Agent修改是JDK的类,类中加入了引用TTL的代码,所以TTL AgentJar要加到bootclasspath上。

Java命令行示例如下:

java -Xbootclasspath/a:transmittable-thread-local-2.0.0.jar \
    -javaagent:transmittable-thread-local-2.0.0.jar \
    -cp classes \
    com.alibaba.ttl.threadpool.agent.demo.AgentDemo

有Demo演示『使用Java Agent来修饰线程池实现类』,执行工程下的脚本run-agent-demo.sh即可运行Demo。

Java Agent的使用方式在什么情况下TTL会失效

由于RunnableCallable的修饰代码,是在线程池类中插入的。下面的情况会让插入的代码被绕过,传递会失效。

  • 用户代码中继承java.util.concurrent.ThreadPoolExecutorjava.util.concurrent.ScheduledThreadPoolExecutor, 覆盖了executesubmitschedule等提交任务的方法,并且没有调用父类的方法。
    修改线程池类的实现,executesubmitschedule等提交任务的方法禁止这些被覆盖,可以规避这个问题。
  • 目前,没有修饰java.util.Timer类,使用Timer时,TTL会有问题。

🔌 Java API Docs

当前版本的Java API文档地址: http://alibaba.github.io/transmittable-thread-local/apidocs/

🍪 Maven依赖

示例:

<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>transmittable-thread-local</artifactId>
	<version>2.0.0</version>
</dependency>

可以在 search.maven.org 查看可用的版本。

❓ FAQ

  • Mac OS X下,使用javaagent,可能会报JavaLaunchHelper的出错信息。
    JDK Bug: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=8021205
    可以换一个版本的JDK。我的开发机上1.7.0_40有这个问题,1.6.0_511.7.0_45可以运行。
    # 1.7.0_45还是有JavaLaunchHelper的出错信息,但不影响运行。

🗿 更多文档

📚 相关资料

Jdk core classes

Java Agent

transmittable-thread-local's People

Contributors

bladehd avatar civanyp avatar gitter-badger avatar misgersameer avatar oldratlee avatar

Watchers

 avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.