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

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

相关内容

热门资讯

关于某讲座的学习记录 《突破心障,不可阻挡》 非常快速学习,非常快速适应 方法论 优秀的人才 ...
红黑树详解 目录 概念 结构  插入  父亲为红,叔叔存在且为红  父亲为红,叔叔...
原创 当... 国家的皇帝可以制定或修改法律,而且一定要按照自己的意图来,哪怕有违伦理道德,也仍然要那么干。权大于法...
2025年山东省暨滨州市“民族... 5月29日下午,2025年山东省暨滨州市“民族宗教政策法规学习月”活动启动仪式在滨州市无棣县举行。省...
【C#】List数据去重 系列文章 【C#】单号生成器(定义编号规则、流水号、产生业务单号) 本文...
Go 基础入门 1. 变量 Go 语言是静态类型语言,由于编译时,编译器会检查变量的类型...
Python日志logging... 一、什么是日志 在《网络安全之认识日志采集分析审计系统》中我们认识了日志。日志数据的核心就是日志消息...
北京国际商事仲裁中心建设条例(... 5月29日,市十六届人大常委会第十七次会议召开,《北京国际商事仲裁中心建设条例(草案)》提请二审。条...
朴素贝叶斯学习报告 报告 朴素贝叶斯算法描述公式:  案例计算步骤: 一个数据集中有两个样本...
新手复现STANet代码详解S... STANet/options/base_options.pyBaseOptions.pyinitia...