TtlExcutors解决父子线程的上下文传递

TtlExcutors解决父子线程的上下文传递

Posted by John Doe on 2021-10-27
Words 663 and Reading Time 3 Minutes
Viewed Times

背景

在项目中出现线程池创建的线程无法获取到创建线程的父线程main线程的信息,采用阿里开源的TtlExcutors线程池解决父子线程上下文传递问题。

简介

官方文档

TTL(transmittable-thread-local)是一个线程间传递ThreadLocal,异步执行时上下文传递的解决方案。 整个库的核心是构建在TransmittableThreadLocal类(继承并加强InheritableThreadLocal类)之上,同时包含线程池修饰(ExecutorService/ForkJoinPool/TimerTask)以及Java Agent支持,代码小于1k行,短小精悍。

Demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
static ThreadPoolExecutor executorService = (ThreadPoolExecutor)Executors.newFixedThreadPool(5);

static {
executorService.prestartAllCoreThreads();
}

public static void main(String[] args) throws InterruptedException {
TransmittableThreadLocal<String> itl = new TransmittableThreadLocal<>();
itl.set("msg");

// 使用TtlRunnable或TtlCallable包装原生回调方法
executorService.execute(Objects.requireNonNull(TtlRunnable.get(() -> {
System.out.println("InheritableThreadLocal ThreadPoolExecutor by TtlRunnable:" + itl.get());
})));

// 使用包装TtlExecutors包装原生的ThreadPoolExecutor
// 1、getTtlExecutor:修饰接口Executor
// 2、getTtlExecutorService:修饰接口ExecutorService
// 3、getTtlScheduledExecutorService:修饰接口ScheduledExecutorService
Executor ttlExecutor = TtlExecutors.getTtlExecutor(executorService);
ttlExecutor.execute(() -> {
System.out.println("InheritableThreadLocal ThreadPoolExecutor by TtlExecutors:" + itl.get());
});

Thread.sleep(10000);
}
1
2
InheritableThreadLocal ThreadPoolExecutor by TtlRunnable:msg
InheritableThreadLocal ThreadPoolExecutor by TtlExecutors:msg

实战使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/**
* ttl线程池配置
* <p>使用方式</p>
* <p>@Resource(name = "ttlExecutorService")</p>
* <p>private ExecutorService ttlExecutorService;</p>
* <p>或者</p>
* <p>在spring实例方法上使用:@Async("ttlExecutorService")</p>
* @author guozhixian
* @date 2021/9/1
*/
@Configuration
public class ttlThreadPoolConfig {

private static final AtomicInteger ATOMIC_INTEGER = new AtomicInteger(1);

private static final int CORE_POOL_SIZE = 4;

private static final int PLZDLX_CORE_POOL_SIZE = 2;

private static final int MAXIMUM_POOL_SIZE = 4;

private static final int KEEP_ALIVE_TIME = 60;

private static final int CAPACITY = 1000;

/**
* 创建文书制作线程池:使用TtlExecutors可以使用AuthContextHolder信息
* <p>阿里开源的线程间上下文传递解决方案</p>
*
* @return ExecutorService
*/
@Bean("ttlExecutorService")
public ExecutorService executorService() {
return TtlExecutors.getTtlExecutorService(new ThreadPoolExecutor(
Runtime.getRuntime().availableProcessors() * CORE_POOL_SIZE,
Runtime.getRuntime().availableProcessors() * MAXIMUM_POOL_SIZE,
KEEP_ALIVE_TIME,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(CAPACITY),
r -> new Thread(r, "Thread-ttl" + ATOMIC_INTEGER.getAndIncrement()),
new MainRejectedExecutionHandler()));
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/**
*
* AuthContextHolder
* @description 授权,用户信息ThreadLocal存储
*/
@Slf4j
public final class AuthContextHolder {

private static final ThreadLocal<AuthInfo> AUTHINFO_HOLDER = new TransmittableThreadLocal<>();

private AuthContextHolder() {}

/**
* UserContextHolder
* @description 清除上下文信息
*/
public static void clearContext() {
log.debug("从线程id:{}中清除信息", Thread.currentThread().getId());
AUTHINFO_HOLDER.remove();
}

/**
*
* UserContextHolder
* @description 获取上下文信息
* @version 1.0
*/
public static AuthInfo getContext() {
log.debug("从线程id:{}中获取信息", Thread.currentThread().getId());
return Optional.ofNullable(AUTHINFO_HOLDER.get()).orElse(new AuthInfo());
}

/**
*
* UserContextHolder
*
* @description 设置上下文信息
* @param user
*/
public static void setContext(AuthInfo user) {
log.debug("从线程id:{}中获取信息", Thread.currentThread().getId());
AUTHINFO_HOLDER.set(user);
}
}

使用:

方式一:Spring注入

1
2
3
4
5
6
7
8
9
10
11
@Resource(name = "ttlExecutorService")
private ExecutorService ttlExecutorService;


@Transactional(rollbackFor = Exception.class)
public void asyncDoThings(){
ttlExecutorService.execute(() -> {
AuthInfo authInfo = AuthContextHolder.getContext();
doSomeThing();
});
}

方式二:@Async注解

1
2
3
4
5
@Async("ttlExecutorService")
public void asyncDoThings() {
AuthInfo authInfo = AuthContextHolder.getContext();
doSomeThing();
}

This is copyright.

...

...

00:00
00:00