博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
浅谈ThreaLocal
阅读量:4964 次
发布时间:2019-06-12

本文共 3516 字,大约阅读时间需要 11 分钟。

ThreadLocal,顾名思义:线程本地变量。它的作用并不是为了线程安全,线程安全的前提是线程之间共享了变量,而ThreadLocal是把变量的引用或者副本作为value。

现在来看第一个例子:

class Thread1 extends  Thread{    StringBuffer s=new StringBuffer("abc");    ThreadLocal
tl=new ThreadLocal<>(); @Override public void run() { tl.set(s); System.out.println(tl.get()); s.append("bac"); tl.set(s); System.out.println(tl.get()); }}public class ThreadLocalTest { public static void main(String[] args) { Thread t1=new Thread1(); Thread t2=new Thread1(); t1.start(); t2.start(); }}

输出结果:

abcabcabcabcabcabc

这边个人觉得有两个问题可以提出

1:为什么要用StringBuffer?

2: StringBuffer为什么不设置为static

3:ThreadLocal为什么没设置为static,在很多文章中都是设置为static的。

第一个问题:因为String是java coder最常用的,但是String是常量而不是变量。StringBuffer作为变量同时是线程安全的。

第二个问题:StringBuffer设置为static会使它也成为共享变量,并且ThreadLocal中保存的只是引用,那么在使用ThreadLocal时对StringBuffer进行修改,就会影响另外一个线程了。

第三个问题:其实是应该使用static的!原因是省内存。。。

class Thread1 extends  Thread{    static StringBuffer s=new StringBuffer("abc");    static ThreadLocal
tl=new ThreadLocal<>(); @Override public void run() { tl.set(s); System.out.println(tl.get()); s.append("bac"); tl.set(s); System.out.println(tl.get()); }}public class ThreadLocalTest { public static void main(String[] args) { Thread t1=new Thread1(); Thread t2=new Thread1(); t1.start(); t2.start(); }}
进行修改代码后的结果 abcabcbacabcbacabcbacbac

 

现在才是重头戏,分析源码

我们来看ThreadLocal的set()方法,这个方法是将value插入到map中的,But?

1:key是什么--> 是ThreadLocal

2:插入到哪里?-->Thread.ThreadLocalMap

ThreadLocal.ThreadLocalMap threadLocals = null;//这是Thread类中的一行代码
(ThreadLocal类,以下全是) public void set(T value) {
Thread t = Thread.currentThread(); 获取当前线程 ThreadLocalMap map = getMap(t); 获取ThreadLocalMap。因为Thread类中有这个变量,但是它并没有进行初始化(第二个问题) if (map != null) 如果当前线程中的ThreadLocalMap!=null,即已经指向一个对象 map.set(this, value); map就进行插入,this指的便是ThreadLocal这个对象,value就是插入的值(第一个问题),这边是会覆盖的。 else 具体的插入就不看了,如果想看,可以看我即将写的HashMap的源码解析 createMap(t, value); 如果为空,进行创建。见下一篇代码
}
void createMap(Thread t, T firstValue) {        t.threadLocals = new ThreadLocalMap(this, firstValue);    }
public T get() {        Thread t = Thread.currentThread();               //获取当前线程        ThreadLocalmap = getMap(t);                      //获取map        if (map != null) {            ThreadLocalMap.Entry e = map.getEntry(this); //通过ThreadLocal这个key从ThreadLocalMap的内部实现获取Entry,见下一篇代码            if (e != null) {                @SuppressWarnings("unchecked")                T result = (T)e.value;                   //获取值                return result;            }        }        return setInitialValue();    }
private Entry getEntry(ThreadLocal
key) { int i = key.threadLocalHashCode & (table.length - 1); 类似hashMap,通过取模作为哈希函数 Entry e = table[i]; if (e != null && e.get() == key) 判断key是否相等,这边没有进行遍历,说明解决冲突的方法不是链地址法 return e; else return getEntryAfterMiss(key, i, e); }

引用一段话:来自http://blog.sina.com.cn/s/blog_d459b83c0102ve6s.html

总之,ThreadLocal不是用来解决对象共享访问问题的,而主要是提供了保持对象的方法和避免参数传递的方便的对象访问方式。归纳了两点: 

1。每个线程中都有一个自己的ThreadLocalMap类对象,可以将线程自己的对象保持到其中,各管各的,线程可以正确的访问到自己的对象。 
2。将一个共用的ThreadLocal静态实例作为key,将不同对象的引用保存到不同线程的ThreadLocalMap中,然后在线程执行的各处通过这个静态ThreadLocal实例的get()方法取得自己线程保存的那个对象,避免了将这个对象作为参数传递的麻烦。

 

转载于:https://www.cnblogs.com/trotyzyq/p/7695796.html

你可能感兴趣的文章
清除浮动
查看>>
PayPal(贝宝)支付接口、文档、IPN
查看>>
ORACLE 10G R2_执行计划中cost cardinality bytes cpu_cost io_cost解释
查看>>
本地存储
查看>>
MP3的播放与停止
查看>>
牛客(59)按之字形顺序打印二叉树
查看>>
JavaScript 图表库 xCharts
查看>>
Android项目的目录结构
查看>>
C++中“引用”的底层实现
查看>>
Spring Cloud与微服务构建:微服务简介
查看>>
Babel 是干什么的
查看>>
cocos2dx-3.0(8)------Label、LabelTTF、LabelAtlas、LabelBMFont使用之法
查看>>
CODE[VS] 1842 递归第一次
查看>>
20180418小测
查看>>
数字三角形
查看>>
NGUI 减少drawcall规则
查看>>
三元表达,匿名函数
查看>>
前端笔记-基础笔记
查看>>
【LeetCode & 剑指offer刷题】查找与排序题6:33. Search in Rotated Sorted Array(系列)
查看>>
GNU/Linux超级本ZaReason Ultralap 440体验
查看>>