自学内容网 自学内容网

ThreadLocal的用法

概述

ThreadLocal提供了线程局部变量,用于在线程中保存数据,在ThreadLocal中保存的数据仅属于当前线程,所以ThreadLocal实例的get或set方法访问自己的独立副本,这些副本之间相互隔离,互不影响

ThreadLocal利用Thread中维护的ThreadLocalMap来保存数据

实例:


public class ThreadLocal_Test01 {
private static ThreadLocal<String> nameLocal=new ThreadLocal<String>();
private static ThreadLocal<String> idLocal=new ThreadLocal<String>();
public static void main(String[] args) {
Thread t1=new Thread(()->{
try {
//保存数据
nameLocal.set("鹭卓");
idLocal.set("001");
//调用方法,重新获取数据
dosth();
}finally {
nameLocal.remove();
idLocal.remove();
}
},"线程1");

Thread t2=new Thread(()->{
try {
//保存数据
nameLocal.set("卓沅");
idLocal.set("008");
//调用方法,重新获取数据
dosth();
} finally {
nameLocal.remove();
idLocal.remove();
}
},"线程2");

t1.start();
t2.start();

}

public static void dosth() {
//通过ThreadLocal,获取当前线程中的数据
String name=nameLocal.get();
System.out.println(Thread.currentThread().getName()+"-->dosth():"+name);

String id=idLocal.get();
System.out.println(Thread.currentThread().getName()+"-->dosth():"+id);
//线程继续调用方法,获取当前线程中的数据
show();
}

public static void show() {
//通过ThreadLocal,获取当前线程中的数据
String name=nameLocal.get();
System.out.println(Thread.currentThread().getName()+"-->show():"+name);

String id=idLocal.get();
System.out.println(Thread.currentThread().getName()+"-->show():"+id);
}
}

运行结果:

ThreadLocal常用方法

1、存储数据至当前线程的ThreadLocalMap:public void set(T value);

2、从当前线程的ThreadLocalMap中获取数据:public T get();

3、从当前线程的ThreadLocalMap中删除数据:public void remove();

ThreadLocalMap内部结构

ThreadLocalMap内部数据结构是一个Entry类型的数组,每个Entry对象的key为ThreadLocal对象,value为存储的数据

为什么使用ThreadLocal做key?

如果应用中,一个线程中只使用一个ThreadLocal对象,那么使用Thread做key可以,代表每一个Thread线程对应一个value

如果一个线程中不只使用了一个ThreadLocal对象,这时就不能用Thread做key,因为key值是唯一的

父子线程如何共享数据?

使用ThreadLocal是不行的,main方法在主线程中执行的,相当于父线程,在main方法中开启另一个线程相当于子线程,两个线程对象拥有不同的ThreadLocalMap,不能共享数据

例子

//父子线程传递数据
public class ThreadLocal_Test02 {
public static void main(String[] args) {

ThreadLocal<String> local=new ThreadLocal<String>();

local.set("天王盖地虎");
System.out.println("主线程:"+local.get());

//创建子线程
Thread t=new Thread(()->{
System.out.println("子线程:"+local.get());
});
t.start();
}
}

运行结果:

使用InheritableThreadLocal,它是JDK自带的类,继承自ThreadLocal类

例子:


//父子线程传递数据
public class ThreadLocal_Test02 {
public static void main(String[] args) {

//ThreadLocal<String> local=new ThreadLocal<String>();

//允许子线程与父线程共享数据
InheritableThreadLocal<String> local=new InheritableThreadLocal<String>();

local.set("天王盖地虎");
System.out.println("主线程:"+local.get());

//创建子线程
Thread t=new Thread(()->{
System.out.println("子线程:"+local.get());
});
t.start();
}
}

运行结果:

ThreadLocal如何避免内存泄露?

在使用完ThreadLocal对象后,在finally中调用ThreadLocal对象的remove()方法

remove()方法中会把Entry中的key和value都设置成null,这样就能被GC及时回收,无需触发额外的清理机制,所以能解决内存泄漏问题

ThreadLocal应用场景

  • 多线程环境下的资源隔离:在多线程应用中,每个线程可能需要独立的变量副本,如数据库连接、用户会话信息等。使用ThreadLocal可以避免多个线程之间对这些资源的共享冲突。例如,在一个 Web 应用中,每个用户请求可能由一个单独的线程处理,使用ThreadLocal可以为每个线程存储独立的用户会话相关的变量,如用户 ID、权限等。

例如:SqlSession会话对象绑定,避免多个线程使用同一个SqlSession对象,由于关闭导致异常

  • 线程上下文信息传递ThreadLocal可以用于在同一个线程的不同方法之间传递信息,而不需要显式地在方法参数中传递这些信息。例如,在一个复杂的业务逻辑处理过程中,多个方法可能都需要访问当前线程相关的一些上下文信息,如事务 ID 等,可以使用ThreadLocal来存储和传递这些信息。

例如spring中存储的request请求信息


原文地址:https://blog.csdn.net/Z_DOUBLE_Y/article/details/142390462

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!