ThreadLocal的一些自己的理解
来源:互联网 发布:h5切水果游戏源码 编辑:程序博客网 时间:2024/05/22 02:51
有关于ThreadLocal的原理的源代码解释在下面已经说的很清楚了 源代码也很清晰易懂
http://www.cnblogs.com/dolphin0520/p/3920407.html
个人对于ThreadLocal类的一些总结:
1.
ThreadLocal类并不是将线程和所存储的对象进行键值保存的和进行取值的(这是我第一反应以为的)
而是将存储的值保存到对应Thread对象的ThreadLocalMap里,ThreadLocalMap的实现原理类似于hashMap,
内部有一个Entry数组,一个Entry通常至少包括key,value, 查找时通过一定的运算规则运算Key的HASH值,来得到Entry在数组中的位置,进而得到相应的value。
但是这个ThreadLocalMap是将当前ThreadLocal对象实例传入当作键值,将set的对象当value值进行存储
下面是ThreadLocal的set方法源码
public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value);//将this传入 else createMap(t, value); }
private void set(ThreadLocal key, Object value) { // We don't use a fast path as with get() because it is at // least as common to use set() to create new entries as // it is to replace existing ones, in which case, a fast // path would fail more often than not. Entry[] tab = table; int len = tab.length; int i = key.threadLocalHashCode & (len-1);//对key进行hash运算 存储 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; } } tab[i] = new Entry(key, value); int sz = ++size; if (!cleanSomeSlots(i, sz) && sz >= threshold) rehash(); }
取值时也根据对应的thread对象拿出自己的threadLocalMap,再根据threadLocal的实例为键值得到对应本线程本ThreadLocal的副本
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(); }
2
每个threadLocalMap对应每个线程只能存储一个对象
也就是说你set了一个对象A,再放入对象B ,对象B就会把对象A取代 这就跟HashMap一样
因为ThreadLocal是键值.。通过以上的代码也能看出来
3.
先看一段代码
public class Test{public int i = 1;static ThreadLocal<Object> t = new ThreadLocal<Object>();public static void main(String[] args){Test test = new Test();Test test1 = new Test();MyThread m1= new MyThread(2,test,true);//MyThread m2 = new MyThread(3,test1,false);MyThread m2 = new MyThread(3,test,false);Thread t1 = new Thread(m1);Thread t2 = new Thread(m2);t1.start();t2.start();}}class MyThread implements Runnable{int obj;boolean flag;Test t;public MyThread(int i,Test t ,boolean flag){this.obj = i;this.t=t;this.flag=flag;}@Overridepublic void run(){Test.t.set(obj);//该放入的对象被后面的所取代Test.t.set(t);//只在run期间threadLocals是保存的 run之后threadLocals置空//并不是由threadLocal给你克隆 副本 而是由你自己来设置放进去的副本Test t = (Test) get();if(flag==false){try{Thread.sleep(5000);//睡眠 确保另外一个线程已经操作结束} catch (InterruptedException e){// TODO Auto-generated catch blocke.printStackTrace();}}System.out.println("线程为"+Thread.currentThread().getId()+"原来的:"+t.i);t.i = obj;//改变值System.out.println("线程为"+Thread.currentThread().getId()+"现在的:"+((Test)get()).i);System.out.println("线程为"+Thread.currentThread().getId()+"所存储的对象:"+get());}public Object get(){return Test.t.get();}}
此时输出如下:
线程为9原来的:1线程为9现在的:2线程为9所存储的对象:ThreadLocalTest.Test@65b8b5cd线程为10原来的:2线程为10现在的:3线程为10所存储的对象:ThreadLocalTest.Test@65b8b5cd
我在两个线程放入了同一个Test对象test,当然run方法里也set了这个test
像我刚开始以为ThreadLocal会自动为每个线程创建一个副本(好可笑的梦哈)
这段代码也证实了并不会。
所以并不是由ThreadLocal给你克隆副本,而是由你自己来设置放进去的副本
如果将注释的代码代替
则输出如下:
线程为9原来的:1线程为9现在的:2线程为9所存储的对象:ThreadLocalTest.Test@65b8b5cd线程为10原来的:1线程为10现在的:3线程为10所存储的对象:ThreadLocalTest.Test@72d2ee5d
上面啰嗦一大堆 就是为了让我自己认识到ThreadLocal需要自己来设置对应每个线程的副本
而这就需要执行ThreadLocal的set方法 或者重写ThreadLocal的initialValue方法
如同下面这样:
static ThreadLocal<Object> t = new ThreadLocal<Object>(){public Object initialValue(){return new Test();}};
- ThreadLocal的一些自己的理解
- ThreadLocal源码的一些理解
- java ThreadLocal 自己的一些见解
- scrollTop自己的一些理解
- 自己对ThreadLocal的理解(作为讨论)
- 理解高并发(18).编写自己的threadlocal
- 对ThreadLocal的理解
- ThreadLocal的理解
- ThreadLocal的理解
- 关于ThreadLocal的理解
- 对ThreadLocal的理解
- ThreadLocal的理解(转载)
- ThreadLocal类的理解
- ThreadLocal的理解
- ThreadLocal 的理解
- ThreadLocal的理解
- ThreadLocal的个人理解
- 关于ThreadLocal的理解
- javascript数字类型number类型方法
- centos 7 修改hostname正确做法
- MVVM前端框架个人见解
- http错误码
- 如何在高并发分布式系统中生成全局唯一Id
- ThreadLocal的一些自己的理解
- Hibernate通用Dao实现
- listview 适配器多类型
- Head First 设计模式之工厂模式(Factory Pattern)
- 微信小程序开发
- 一个自己编的小游戏——猜数
- 基于线程池和NIO技术构建高效的多协议Android通讯框架(转)
- ecplise文件之间的关系
- java.util.Collections.unmodifiableList()方法实例