最近围观@田麦大牛的代码,看到ThreadLocal还能这么玩,故此记录一下
ThreadLocal概念:http://blog.csdn.net/qjyong/article/details/2158097
可以明显看到ThreadLocal中的值是和线程本身绑定的,那么如果我在A线程中使用了ThreadLocal,set了一个变量,然后在B线程如何取出来呢。
往ThreadLocal中set变量时,可以debug这个类,发现类中除了一串hashCode外什么都没有,那么这个值究竟放在哪里呢?
threadLocalHashCode = -387276957
看一下ThreadLocal的set方法
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
可以看到ThreadLocal的变量全部是存储在Thread的
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
中,由于ThreadLocalMap是不可见的,所以只能通过反射的方式去调用。
到此为止,ThreadLocal就已经与线程并非完全相关了,你大可以对ThreadLocalMap进行copy,在采用事件回调等机制不同线程的情况下也可以run的很愉快了。完整代码如下:
public abstract class Task implements Runnable {
Object threadLocal;
public Task(Object threadLocalMap){
this.threadLocal =threadLocalMap;
}
public final void run(){
BeanUtils.forceSetProperties(Thread.currentThread(), threadLocal, "threadLocals");
realRun();
}
protected abstract void realRun();
}
例子:
public class ThreadLocalTest {
private static final ThreadLocal<String> tl = new ThreadLocal<String>();
static class MyTask extends Task{
public MyTask(Object threadLocal){
super(threadLocal);
}
@Override
public void realRun() {
System.out.println("I'm Thread:"+Thread.currentThread().getName()+", value is:"+tl.get());
}
}
public static void main(String[] args) {
tl.set("hello world");
Object threadLocals = BeanUtils.forceGetProperties(Thread.currentThread(),"threadLocals");
Executors.newSingleThreadExecutor().submit(new MyTask(threadLocals));
System.out.println("I'm Thread:"+Thread.currentThread().getName()+", value is:"+tl.get());
}
}
BeanUtils:
public static Object forceGetProperties(Object object, String fieldName){
try {
Field field = object.getClass().getDeclaredField(fieldName);
if (!field.isAccessible()){
field.setAccessible(true);
}
return field.get(object);
} catch (Exception e) {
//ignore
return null;
}
}
public static void forceSetProperties(Object target,Object arg, String fieldName){
try {
Field field = target.getClass().getDeclaredField(fieldName);
if (!field.isAccessible()){
field.setAccessible(true);
}
field.set(target,arg);
} catch (Exception e) {
//ignore
}
}
运行结果:
I'm Thread:main, value is:hello world
I'm Thread:pool-1-thread-1, value is:hello world