0
点赞
收藏
分享

微信扫一扫

ThreadLocal的用法

Spinach菠菜 2024-09-21 阅读 24

概述

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常用方法

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

举报

相关推荐

0 条评论