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请求信息

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值