LocalThread分析

来源:互联网 发布:win8垃圾清理软件 编辑:程序博客网 时间:2024/06/08 05:37
LocalThread源码分析:
一、首先看看LocalThread是干嘛的
外面能够看到的方法就以下四个:
get()  
protected  T initialValue() 。 
void remove()  
void set(T value)  
可以猜测这是一个管理集合的类。


二、再看看里面的一些方法
1.构造方法:空的,那就不管
2.get
public T get() {        Thread t = Thread.currentThread();        ThreadLocalMap map = getMap(t);        if (map != null) {            ThreadLocalMap.Entry e = map.getEntry(this);            if (e != null) {                @SuppressWarnings("unchecked")                T result = (T)e.value;                return result;            }        }        return setInitialValue();    }


简单的看就2步:
-得到当前的线程,并且调用getMap方法得到一个Map
-从Map中取,以当前对象this为key取。
ThreadLocalMap getMap(Thread t) {return t.threadLocals;}


传入Thread对象,得到他的threadLocals属性。
(看到这里才发现原来ThreadLocal与Thread都是java.lang包的,以前都没用过ThreadLocal,真是有点low了)
而且Thread和ThreadLocal的连接的非常紧密:在Thread中有一个ThreadLocalMap(ThreadLocal的内部类)属性,也就是上面的threadLocals属性,看来这都是设计好的。

再看看setInitialValue:
private T setInitialValue() {        T value = initialValue();        Thread t = Thread.currentThread();        ThreadLocalMap map = getMap(t);        if (map != null)            map.set(this, value);        else            createMap(t, value);        return value; }


首先是这个方法的调用时机:
在threadLocals为空或者其中没有key为this的value的时候调用,而且在Thread中看了一下也没找到给threadLocal赋值的操作,这个属性在Thread中好像就是专门给ThreadLocal留的。
那就先假想如果什么都没做,直接new出TheadLocal,调用get方法,那么这个时候走的是这个方法
再看看方法内部的执行:
首先调用initialValue方法,得到一个value,这个方法是protected,也就是需要子类重写的。
然后获取当前线程对应的那个ThreadLocalMap,然后判断map是否空,不是空,设置进去,这个简单。如果是空,则调用createMap,看方法名就是创建一个map的意思。
void createMap(Thread t, T firstValue) {t.threadLocals = new ThreadLocalMap(this, firstValue);}


这个方法也很简单,new出来一个ThreadLocalMap,传入2个参数。这里一行代码相当于做了两件事情:
1.new一个map
2.将key,value当做map的第一个键值对(这个map好像也就存一个键值对,后面再说)
最后返回的还是value,以前map中存的value或者说是initialValue返回的。


3.set:
public void set(T value) {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null)map.set(this, value);elsecreateMap(t, value);}


这个方法应该很简单了,和setInitialValue干的事还简单。


4.remove:
 public void remove() {         ThreadLocalMap m = getMap(Thread.currentThread());         if (m != null)             m.remove(this);}


看一下方法,一眼就能看懂


三、总结一下ThreadLocal的工作流程

总的来说就是一个集合管理器,如果当做是个黑盒子的话,可以就把他看成是一个map。
不同的线程都可以调用这个类的对象的set,get方法,因为里面用的是Thread.currentThread当做key,所以东西存在这里面不同的线程得到的是不一样的。
又因为set里面能传一个参数,即value,key默认为当前thread。get无参数,key同上,所以对于一个线程来说只能存放一个对象。
要想再存点,再new ThreadLocal把。
ThreadLocal管理的集合最大的好处就是相同的线程共享,不同的线程不干预。


四、使用ThreadLocal的优点

ThreadLocal它是jdk自带的,而且与Thread都在在java.lang包,两者的关系已经设计好(Thread中有个他的Map属性)。
其实优点就要归结于Thread中给的LocalThreadMap这个属性:
有了这个属性,每个线程独有一个Map,在get的时候,直接得到对应线程自己的map,再去里面取,不会涉及到任何的锁操作。效率高。


之前我也写过一个简单的TransactionManager,里面的Map也用于存放各线程的数据,不过他的key也是当前thread对象,所有的线程一起访问里面的资源就有可能发生资源共享问题,所以里面加了好多锁来控制。
在上一篇博客中不愿意用TransactionManager的原因也是这样,明明不复杂的东西,还要加几个锁,感觉好不舒服,现在发现ThreadLocal就能避免一些带来的问题,jdk他自己设计好的用起来就是方便。


五、个人的看法

既然Thread中提供了ThreadLocalMap,也有ThreadLocal来管理,那就用它没错。
如果没有提供,那自己写map再加锁管理应该也没错。


事件编程的时候以前给按钮写监听器,传入一个接口实现类的子对象,那时候觉得很神奇(怎么把这个方法放进去的?),也不知道其中的原理。
后来知道这个是靠回调实现的。
没有回调,方法就执行不了。


编程的时候有些时候就得留接口,留回调,这样后面处理起来就方便了。





0 0
原创粉丝点击