TheadLocal可以为每个线程保存线程独有的变量,线程可以修改ThreadLocal保存的变量, 其他线程不可见,达到线程间隔离的目的。
ThreadLocal使用
public class ThreadLocalTest { private static final ThreadLocal<String> threadLocal = new ThreadLocal(); public String get() { return threadLocal.get(); } public void set(String ThreadName) { threadLocal.set(ThreadName); } public void remove() { threadLocal.remove(); } public static void main(String [] args) { ThreadLocalTest threadLocalTest = new ThreadLocalTest(); System.out.println(threadLocalTest.get()); Thread t1 = new Thread(){ @Override public void run() { threadLocalTest.set(getName()); for (int i=0; i<5; i++) { System.out.println(threadLocalTest.get()); } } }; Thread t2 = new Thread(){ @Override public void run() { threadLocalTest.set(getName()); for (int i=0; i<5; i++) { System.out.println(threadLocalTest.get()); } } }; t1.start(); t2.start(); try { t1.join(); t2.join(); } catch (InterruptedException e) { e.printStackTrace(); } }
如上面代码所示:ThreadLocal对象可以通过new ThreadLocal()创建。
ThreadLocal可以设置初始变量,这样threadlocal在调用get方法的时候,如果没有调用过threadLocal set方法,会获取到这个初始值。
初始化变量有两种方法
1. 创建ThreadLocal子类,并重写initialValue方法。最简单的方式是通过匿名类创建ThreadLocal子类。
private static final ThreadLocal<String> threadLocal = new ThreadLocal<String>(){ @Override protected String initialValue() { return "start"; } };
2. 使用ThreadLocal的静态工厂方法withInitial, 传入Supplier
的子类。
ThreadLocal.withInitial(() -> "start")
ThreadLocal使用场景
1. 存储线程不安全的对象,同时对象不用在各线程之间共享。如jdk中日期时间格式化类SimpleDataFormat的对象
2. 在web应用中,存储请求状态数据。通常会在servlet filter或者spring interceptor中,使用ThreadLocal记录请求状态数据,比如请求的trace id。
ThreadLocal内部原理
ThreadLocal内部核心是ThreadLocalMap, ThreadLocalMap key是ThreadLocal对象,value是待存储的值。ThreadLocalMap不同于HashMap, ThreadLocalMap里面的Entry是WeakReference。ThreadLocalMap采用开放寻址法。