忽然发现还有个更牛逼的:https://github.com/alibaba/transmittable-thread-local
ThreadLocal一个很有用的场景:收到请求,框架解析出用户User对象,保存到ThreadLocal中,然后Controller、Service中就可以直接从ThreadLocal中来获取User对象了。大部分时候,这已经足够了,直到遇到了ThreadPool。ThreadPool中的线程是不会被销毁的,而且很明显跟主线程不是同一个线程,那么主线程中的ThreadLocal是无法直接传递到ThreadPool的线程里面的!再ThreadPool的场景下,显然InheritableThreadLocal是无用武之地的,下面我们就来简单的封装下。
这是我们的用来异步执行任务的ThreadPoolUtil:
public class ThreadPoolUtil {
private final ExecutorService executor;
private static ThreadPoolUtil instance = new ThreadPoolUtil();
private ThreadPoolUtil() {
this.executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2);
}
public static ThreadPoolUtil getInstance() {
return instance;
}
public static <T> Future<T> execute(final Callable<T> runnable) {
return getInstance().executor.submit(runnable);
}
public static Future<?> execute(final Runnable runnable) {
return getInstance().executor.submit(runnable);
}
}
既然无法直接从主线程传递到ThreadPool里面的线程,那就只能用参数来传递了:
public static abstract class ParamRunnable<T> implements Runnable{
private T param;
public ParamRunnable(Supplier<T> paramSupplier) {
if(paramSupplier != null) {
this.param = paramSupplier.get();
}
}
@Override
public void run() {
run(param);
}
public abstract void run(T param);
}
我们创建Runnable的子类,在构造函数中把参数传递进去,这里传递一个Supplier而非参数本身,参数由Supplier提供出来,在run()方法中调用abstract的run()同时把参数传递出去。同理我们继续写一个ParamCallable:
public static abstract class ParamCallable<R,P> implements Callable<R>{
private P param;
public ParamCallable(Supplier<P> paramSupplier) {
if(paramSupplier != null) {
this.param = paramSupplier.get();
}
}
@Override
public R call() {
return call(param);
}
public abstract R call(P param);
}
看一下如何来使用:
public static class User{
private int id;
public User() {}
public User(int id) {
this.id= id;
}
public String toString() {
return "User [id=" + id + "]";
}
}
public static class UserProvider{
private static ThreadLocal<User> userHolder = new ThreadLocal<User>();
public static void setUser(User user) {
userHolder.set(user);
}
public static User getUser() {
return userHolder.get();
}
}
public static void main(String[] args)throws Exception {
UserProvider.setUser(new User(1));
System.out.println(UserProvider.getUser());
ThreadPoolUtil.execute(new ParamRunnable<User>(UserProvider::getUser) {
@Override
public void run(User user) {
System.out.println(user);
}
});
System.in.read();
}
完整的代码见:https://github.com/xjs1919/util/blob/master/src/main/java/com/github/xjs/util/ThreadPoolUtil.java