ThreadLocal原理详解
创始人
2025-05-28 02:54:41
0

一.对ThreadLocal的理解

ThreadLocal为变量在每个线程中都创建了一个副本,一个ThreadLocal在一个线程中是共享的,在不同线程之间又是隔离的,也就说说每个线程都只能看到自己线程的值。

二.ThreadLocal的核心作用

实现线程范围的局部变量

三.ThreadLocla的API介绍

initialValue():返回此线程局部变量的当前线程的初始值,默认为null

get():返回当前线程的此线程局部变量的副本中的值

set(T value):将当前线程的此线程局部变量的副本设器为指定的值。

remove():删除此线程局部变量的当前线程的值。

withInitial(Supplier supplier):创建线程局部变量。

四.ThreadLocal应用

package com.tangbb.test1;/*** @DESCRIPTION:* @USER: tangbingbing* @DATE: 2023/3/13 9:49*/
public class test1 {private static ThreadLocal num = new ThreadLocal() {// 重写这个方法,可以修改“线程变量”的初始值,默认是null@Overrideprotected Integer initialValue() {return 0;}};public static void main(String[] args) {// 创建一号线程new Thread(new Runnable() {@Overridepublic void run() {// 在一号线程中将ThreadLocal变量设置为1num.set(1);System.out.println("一号线程中ThreadLocal变量中保存的值为:" + num.get());}}).start();// 创建二号线程new Thread(new Runnable() {@Overridepublic void run() {num.set(2);System.out.println("二号线程中ThreadLocal变量中保存的值为:" + num.get());}}).start();//为了让一二号线程执行完毕,让主线程睡500mstry {Thread.sleep(500);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println("主线程中ThreadLocal变量中保存的值:" + num.get());}
}

在类中创建一个静态的ThreadLocal变量,在主线程中创建两个线程,在这两个线程中分别设置ThreadLocal变量为1和2。然后等待一号和二号线程执行完毕后,在主线程中查看ThreadLocal变量的值

五.原理分析

每个Thread对象都有一个ThreadLocalMap,当创建一个ThreadLocal的时候,就会将该ThreadLocal对象添加到该Map中,其中键就是ThreadLocal,值可以是任意类型。

 

ThreadLocal 提供了线程本地的实例。它与普通变量的区别在于,每个使用该变量的线程都会初始化一个完全独立的实例副本。ThreadLocal 变量通常被private static修饰。当一个线程结束时,它所使用的所有 ThreadLocal 相对的实例副本都可被回收。

六.回收举例(解决OOM问题)

为了防止OOM问题ThreadLocal在使用的时候要及时remove

package com.tangbb.test1;/*** @DESCRIPTION:* @USER: tangbingbing* @DATE: 2023/3/13 9:49*/
public class test1 {private static ThreadLocal localVar = new ThreadLocal();static void print(String str) {//打印当前线程中本地内存中本地变量的值System.out.println(str + " :" + localVar.get());//清除本地内存中的本地变量localVar.remove();}public static void main(String[] args) throws InterruptedException {new Thread(new Runnable() {public void run() {test1.localVar.set("local_A");print("A");//打印本地变量System.out.println("after remove : " + localVar.get());}},"A").start();Thread.sleep(1000);new Thread(new Runnable() {public void run() {test1.localVar.set("local_B");print("B");System.out.println("after remove : " + localVar.get());}},"B").start();}}

七.ThreadLocal常见的使用场景

ThreadLocal可以解决具有以下两个需求的场景:

1.每个线程需要有自己单独的实例

2.实例需要在多个方法中共享,但不希望被多线程共享

场景1

数据跨层传递(controller,service, dao)

比如说我们是一个用户系统,那么当一个请求进来的时候,一个线程会负责执行这个请求,然后这个请求就会依次调用service-1()、service-2()、service-3()、service-4(),这4个方法可能是分布在不同的类中的。

package com.kong.threadlocal;public class ThreadLocalDemo05 {public static void main(String[] args) {User user = new User("jack");new Service1().service1(user);}}class Service1 {public void service1(User user){//给ThreadLocal赋值,后续的服务直接通过ThreadLocal获取就行了。UserContextHolder.holder.set(user);new Service2().service2();}
}class Service2 {public void service2(){User user = UserContextHolder.holder.get();System.out.println("service2拿到的用户:"+user.name);new Service3().service3();}
}class Service3 {public void service3(){User user = UserContextHolder.holder.get();System.out.println("service3拿到的用户:"+user.name);//在整个流程执行完毕后,一定要执行removeUserContextHolder.holder.remove();}
}class UserContextHolder {//创建ThreadLocal保存User对象public static ThreadLocal holder = new ThreadLocal<>();
}class User {String name;public User(String name){this.name = name;}
}执行的结果:service2拿到的用户:jack
service3拿到的用户:jack

场景2

数据库连接,处理数据库事务

相关内容

热门资讯

王毅:日本现职领导人讲了不该讲... 据外交部网站,11月19日至22日,中共中央政治局委员、外交部长王毅应邀赴吉尔吉斯斯坦、乌兹别克斯坦...
陕西兴平失联的12岁双胞胎姐妹... 据大风新闻,11月21日晚7时17分,陕西兴平一对12岁的双胞胎姐妹从家里外出。走的时候还穿着蓝色校...
原创 中... 中国再下一令,日本却辗转从韩国口中才得知这个噩耗,高市有点坐不住了,关键时刻放出猛料,要把美国拉下水...
公园掰手腕致骨折起诉索赔被驳回 公园内一场普通的掰手腕,竟导致手臂骨折、花费数万元医疗费。近日,江苏省苏州工业园区人民法院审理了一起...
护航浙商出海发展 浙江省涉外法... 中新网杭州11月23日电 (钱晨菲 吴怡欣)11月23日,浙江省涉外法律服务合作对接会在杭州举行,浙...
吕文君社媒庆祝夺冠:不只是海港... 2025赛季中超联赛于昨日正式落幕,上海海港队凭借出色的表现,成功捧起了冠军奖杯,成为了中超历史上又...
日本政府顾问:无需等到160关... 日本政府顾问表示,高市早苗政府对日元干预将采取更积极姿态,以抑制日元疲软带来的通胀压力,干预门槛可能...
被摄影师起诉侵权 视觉中国公开... 来源:每日经济新闻 持续两年多的摄影师起诉视觉中国(000681.SZ)侵权一案近日迎来进展。 法...
《哪吒2》被质疑过多使用动捕技... 搜狐娱乐讯 22日,奥斯卡公开的最佳动画长片奖“符合参评资格”大名单中没有《哪吒之魔童闹海》,引发热...
为了少付合同款,湖南一公司诉讼... 华声在线11月23日讯(文/视频 全媒体记者 杨昱 通讯员 胡云淞)为了少支付40万元合同款及利息,...