多线程操作之线程缓存ThreadLocal

java.lang.ThreadLocal的作用

ThreadLocal可以保证当前拿到的变量是属于当前访问的线程。也就是每个线程自己的独立小空间。实现了线程之间的数据隔离。

例子

public class ThreadLocalTest {

private static ThreadLocal<String> tl = new ThreadLocal<String>();

public static void main(String[] args) {
tl.set("哈哈");

new Thread(new Runnable() {

@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ":" + tl.get());
}
}).start();

System.out.println(Thread.currentThread().getName() + ":" + tl.get());
}
}

运行结果:

解释:
虽然主线程main往ThreadLocal里面设置了值并且其也可以拿到值,但是线程Thread-0却没有拿到值,可以看出线程之间的数据隔离。

源码分析

set方法

public void set(T value) {
//获取当前线程
Thread t = Thread.currentThread();
//获取当前线程对应的本地Map映射
ThreadLocalMap map = getMap(t);
//如果map不为空
if (map != null)
//将值设置到本地map中
map.set(this, value);
else//如果map为空
//创建线程本地map,将value值进行初始化
createMap(t, value);
}

void createMap(Thread t, T firstValue) {
//初始化线程本地Map
t.threadLocals = new ThreadLocalMap(this, firstValue);
}

ThreadLocalMap(ThreadLocal firstKey, Object firstValue) {
table = new Entry[INITIAL_CAPACITY];
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
table[i] = new Entry(firstKey, firstValue);
size = 1;
setThreshold(INITIAL_CAPACITY);
}

解释:
① 获取当前线程对应的map,如果map不为空,就将值设置到map中。如果map为空就将创建Map结构,然后将值放入到链表中。
注意:可以发现ThreadLocalMap的构造器采用HashMap的套路,初始化节点数组,然后使用键key进行按位与运算计算数组下标,设置最大临界值为初始化容量。
get方法

public T get() {
// 获取当前线程
Thread t = Thread.currentThread();
// 获取当前线程的本地map映射
ThreadLocalMap map = getMap(t);
// 如果map不为空
if (map != null) {
// 获取映射map的链表
ThreadLocalMap.Entry e = map.getEntry(this);
// 如果节点不为空,返回节点的值
if (e != null)
return (T)e.value;
}
//返回初始化的值
return setInitialValue();
}

private T setInitialValue() {
// 获取初始化时传入的值
T value = initialValue();
// 获取当前线程
Thread t = Thread.currentThread();
// 获取当前线程的本地map映射
ThreadLocalMap map = getMap(t);
// 如果映射map不为空,设置当前值
if (map != null)
map.set(this, value);
else // 如果映射map为空,那么创建map映射,然后初始化值到链表中
createMap(t, value);
return value;
}

解释:
① 首先获取当前线程的本地map映射。
② 如果map不为空,那么就走Hashmap的套路,通过键按位与运算计算下标,然后通过下标获取值。
③ 否则会再判断下map是否为空,如果空就创建下ThreadLocalMap,但是最后的效果就是拿到初始化传入的值,初始化传入的值就是null,除非自己重写initialValue方法。

ThreadLocal的应用场景:
每一个线程都有一个自己的对象,并且可以很多处用到,放到ThreadLocal中便于存取。

 

相关推荐

  • CTO:谁在项目中使用Arrays.asList、ArrayList.subList,就立马滚蛋!
  • ChatGPT VS 运维工程师:Ngnix IP封禁以及实现自动封禁IP
  • 恭喜!刚刚正式发布:中小学近视的学生有救了,不手术、见效快!
  • 大数据OLAP系统(2)——开源组件篇
  • 大数据OLAP系统(1)——概念篇
  • 值了。。。
  • ChatGPT之后何去何从?LeCun新作:全面综述下一代「增强语言模型」
  • 深入浅出Prompt Learning要旨及常用方法
  • 怎样让ChatGPT在其内部训练神经网络?先让它想象自己有4块3090
  • 杭州拟向三孩家庭发放补助2万元;深圳一楼盘送 60 万首付被查处;美司令暗示台湾有事将部署攻击解放军...|酷玩日爆
  • 遭到人工智能“背刺” 的我 | 每日一冷
  • 曾经“狂飙”全国的“小灵通”,为何突然消失了?
  • 二十年!中国造船终于干翻日韩!
  • 选内裤选到眼睛花……
  • 二舅治不好的精神内耗,毕业5年存不到5千的名校生能治?
  • 八股文JAVA编程小程序,单日PV过1000拉
  • logback - 自定义日志脱敏组件,一种不错的脱敏方案
  • “不务正业”的跨国木材公司,不好好伐木,竟卖起了俄罗斯蜂蜜......
  • 花2周时间选出来的内裤,原来“裆下生风”是这种感觉……
  • 她居然把加拿大的国歌改了;扎哈罗娃称,破坏平等国际安全体系的是西方;专家警告:"超级野猪"入侵美国 | 每日大新闻