您的位置:首页 > 其它

ThreadLocal用法和实现原理

2016-10-31 18:31 561 查看
如果你定义了一个单实例的java bean,它有若干属性,但是有一个属性不是线程安全的,比如说HashMap。并且碰巧你并不需要在不同的线程中共享这个属性,也就是说这个属性不存在跨线程的意义。那么你不要sychronize这么复杂的东西,ThreadLocal将是你不错的选择。

举例来说:

import java.util.HashMap;

public class TreadLocalTest {

static ThreadLocal<HashMap> map0 = new ThreadLocal<HashMap>(){

@Override

protected HashMap initialValue() {

System.out.println(Thread.currentThread().getName()+"initialValue");

return new HashMap();

}

};

public void run(){

Thread[] runs = new Thread[3];

for(int i=0;i<runs.length;i++){

runs[i]=new Thread(new T1(i));

}

for(int i=0;i<runs.length;i++){

runs[i].start();

}

}

public static class T1 implements Runnable{

int id;

public T1(int id0){

id = id0;

}

public void run() {

System.out.println(Thread.currentThread().getName()+":start");

HashMap map = map0.get();

for(int i=0;i<10;i++){

map.put(i, i+id*100);

try{

Thread.sleep(100);

}catch(Exception ex){

}

}

System.out.println(Thread.currentThread().getName()+':'+map);

}

}

/**

* Main

* @param args

*/

public static void main(String[] args){

TreadLocalTest test = new TreadLocalTest();

test.run();

}

}

输出解释;

Thread-1:start

Thread-2:start

Thread-0:start

Thread-2initialValue

Thread-1initialValue

Thread-0initialValue

Thread-1:{0=100, 1=101, 2=102, 3=103, 4=104, 5=105, 6=106, 7=107, 8=108, 9=109}

Thread-2:{0=200, 1=201, 2=202, 3=203, 4=204, 5=205, 6=206, 7=207, 8=208, 9=209}

Thread-0:{0=0, 1=1, 2=2, 3=3, 4=4, 5=5, 6=6, 7=7, 8=8, 9=9}

可以看到map0 虽然是个静态变量,但是initialValue被调用了三次,通过debug发现,initialValue是从map0.get处发起的。而且每个线程都有自己的map,虽然他们同时执行。

进入Theadlocal代码,可以发现如下的片段;

public T get() {

Thread t = Thread.currentThread();

ThreadLocalMap map = getMap(t);

if (map != null) {

ThreadLocalMap.Entry e = map.getEntry(this);

if (e != null)

return (T)e.value;

}

return setInitialValue();

}

通过阅读源码,了解到, Thread 类内部有一个属性 ThreadLocalMap ,这个属性是以当前线程为key的map,value 存储的就是当前线程的变量。

map0.get() 方法调用的时候,

内部逻辑:获取当前线程的属性ThreadLocalMap,如果不为null,就通过key =当前线程 获取对应的value,

如果为null, 就初始化这个属性,

初始化的逻辑: 先调用initialValue 方法生成一个value,然后 获取ThreadLocalMap,判断map
是否存在,如果存在,则set key/value

key 为当前线程,value 为初始化的值,如果
map不存在,则创建map ,内部逻辑: 给当前线程的ThreadLocalMap 赋值为 new ThreadLocalMap(当前线程,value),

最后返回的就是这个 value,

下次再次调用的时候,这个value也是线程 的私有属性。

所以就实现了多线程调用类,却不共享属性的需求。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: