您的位置:首页 > 其它

深入了解ThreadLocal

2017-06-01 23:26 357 查看
  最近阅读了importNew的一篇关于ThreadLocal的文章:

http://www.importnew.com/17849.html

  因为之前自己也没怎么用过,所以一直也没搞懂,后来查了好多资料以后,我终于能理解里面的实现原理了。

  在这里我给这篇文章的一些内容做个注解吧,重复的地方我也不说了。

ThreadLocal的用法

  ThreadLocal的作用是声明出一些变量,T就相当于你所声明的变量。

  

//声明一个泛型为Long类型的ThreadLocal
ThreadLocal<Long> longLocal=new ThreadLocal();


  longLocal可以算是一个特殊的long对象,它既不是链接文中的第一种情况:多个线程共享同一个变量。也不是第二种情况那样,每次调用都要新建一个新的变量。而是一种近似折中的方案:为每一个会调用这个变量的线程,在第一次调用或者修改longLocal的时候创建一个类型为ThreadLocal的变量。

  原文中的”副本”这个词我觉得还是有差的,因为我觉得这个的本质还是在每个调用的线程里面创建一个全新的longLocal变量,通过set和get方法实现对每个线程里面的longLocal变量的访问和修改。以达到和在每个线程里面创建一个独立的long一样的效果。这样在一些特定的环境中,比如数据库的访问链接上,我们既希望链接函数是静态的,这样方便为每个线程所调用,又不希望每个线程共享同一个链接。在这种情况下,ThreadLocal就可以很好地优化效率和代码风格了。

  具体这是怎么实现的呢?我们看看java内部的代码:

//在Thread类里面有这样一行,threadLocals是一个类似于HashMap的对象,目的在于如果程序里面有多个ThreadLocal变量,对于这个线程而言,用一个哈希表来储存这个线程里面所创建的threadLocal变量,并通过ThreadLocalMap来进行检索。
ThreadLocal.ThreadLocalMap threadLocals = null;


  可能看到这里,还是有点蒙,那就再看看ThreadLocal类的内部类ThreadLocalMap 的set方法。

  

private void set(ThreadLocal<?> key, Object value) {
Entry[] tab = table;
int len = tab.length;
int i = key.threadLocalHashCode & (len-1);

for (Entry e = tab[i];
e != null;
e = tab[i = nextIndex(i, len)]) {
ThreadLocal<?> k = e.get();

if (k == key) {
e.value = value;
return;
}

if (k == null) {
replaceStaleEntry(key, value, i);
return;

a8f7
}
}

tab[i] = new Entry(key, value);
int sz = ++size;
if (!cleanSomeSlots(i, sz) && sz >= threshold)
rehash();
}


  再看看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);
}


  我们先来看看一般情况,当我们在一个线程里面调用longLocal里面的set方法,并传入一个long参数时,程序先通过Thread.currentThread()方法获取当前运行的线程,比如:你在main方法中运行的,那获得的是main线程,在你定义的Thread中运行的,那就获得你所定义的Thread。然后在跑longLocal.set(long)方法的这个线程里面给ThreadLocalMap写入一个你传进去的long变量。其中map的key是longLocal,而value就是你要写入的long。

  同理,对于get方法:

public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
T result = (T)e.value;
return result;
}
}
return setInitialValue()
}


  当你在这个线程里面想找到你set进去的变量的时候,它就会以longLocal作为key去取出你映射进去的value。这就是整个ThreadLocal的作用机理,其中还有很多相关的细节,可以参考链接中的文章以及java里面的源代码。

  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: