面试过程中遇到一个问题,web项目中Controller和Service层之间怎么传递数据(除了使用参数传递)
当时首先想到ThreadLocal,但是没说出来,以后面试中想到什么就尽量说出来不要怕说错
但是没有对ThreadLocal做深入了解所以接下来的问题也是一问三不知
主线程新起线程后,两个线程之间的ThreadlLocal之间的关系?
其实没有关系,就是想让你说出来 新线程中ThreadLocal是对主线程的复制,之后主线程中在对ThreadLocal修改,不会影响新起线程中的内容
关于具体实现
每个Thread对象中,都有一个ThreadLocalMap类型的对象,该map是以本线程中的ThrealLoacl对象为key,以ThreadLoacl的值为value
Thread对象中的ThreadLocalMap默认是null。所以使用get前必须先set,如果不set的话就得重写initialValue方法。
-
public class SequenceB implements Sequence {
-
//private static ThreadLocal num = new ThreadLocal();
-
private static ThreadLocal<Integer> seqNum = new ThreadLocal<Integer>() {
-
public Integer initialValue() {
-
return 0;
-
}
-
};
-
@Override
-
public int getNum() {
-
// TODO Auto-generated method stub
-
seqNum.set(seqNum.get()+1);
-
return seqNum.get();
-
}
-
public static void main(String []args){
-
SequenceB sb = new SequenceB();
-
new Thread(new ClientThread(sb),"thread1").start();
-
new Thread(new ClientThread(sb),"thread2").start();
-
new Thread(new ClientThread(sb),"thread3").start();
-
}
-
-
}
get()方法是用来获取ThreadLocal在当前线程中保存的变量副本,set()用来设置当前线程中变量的副本,remove()用来移除当前线程中变量的副本,initialValue()是一个protected方法,一般是用来在使用时进行重写的,它是一个延迟加载方法,下面会详细说明。
首先我们来看一下ThreadLocal类是如何为每个线程创建一个变量的副本的。
先看下get方法的实现:
第一句是取得当前线程,然后通过getMap(t)方法获取到一个map,map的类型为ThreadLocalMap。然后接着下面获取到键值对,
注意这里获取键值对传进去的是 this,而不是当前线程t。
如果获取成功,则返回value值。
如果map为空,则调用setInitialValue方法返回value。
我们上面的每一句来仔细分析:
首先看一下getMap方法中做了什么:
可能大家没有想到的是,在getMap中,是调用当期线程t,返回当前线程t中的一个成员变量threadLocals。
那么我们继续取Thread类中取看一下成员变量threadLocals是什么:
********************************
******************************
实际上就是一个ThreadLocalMap,这个类型是ThreadLocal类的一个内部类,我们继续取看ThreadLocalMap的实现:
可以看到ThreadLocalMap的Entry继承了WeakReference,并且使用ThreadLocal作为键值。
然后再继续看setInitialValue方法的具体实现:
很容易了解,就是如果map不为空,就设置键值对,为空,再创建Map,看一下createMap的实现:
至此,可能大部分朋友已经明白了ThreadLocal是如何为每个线程创建变量的副本的:
首先,在每个线程Thread内部有一个ThreadLocal.ThreadLocalMap类型的成员变量threadLocals,这个threadLocals就是用来存储实际的变量副本的,键值为当前ThreadLocal变量,value为变量副本(即T类型的变量)。
初始时,在Thread里面,threadLocals为空,当通过ThreadLocal变量调用get()方法或者set()方法,就会对Thread类中的threadLocals进行初始化,并且以当前ThreadLocal变量为键值,以ThreadLocal要保存的副本变量为value,存到threadLocals。
然后在当前线程里面,如果要使用副本变量,就可以通过get方法在threadLocals里面查找。
http://www.cnblogs.com/dolphin0520/p/3920407.html
http://www.cnblogs.com/digdeep/p/4510875.html
阅读(673) | 评论(0) | 转发(0) |