ThreadLocal
1.ThreadLocal为什么能做到线程隔离?
public class ThreadLocal1 { static ThreadLocal<People> t1 = new ThreadLocal<>(); public static void main(String[] args) { new Thread(()->{ try { Thread.sleep(1000); t1.set(new People("zhangsan")); System.out.println(t1.get()); } catch (InterruptedException e) { e.printStackTrace(); } }).start(); new Thread(()->{ try { Thread.sleep(2000); System.out.println(t1.get()); } catch (InterruptedException e) { e.printStackTrace(); } }).start(); } static class People{ String name = null; public People(String name) { this.name = name; } } }
可以看到t1是一个全局变量,为什么在第一个线程中塞入值,并可以打印里面对象。可是在第二个线程中打印t1里面的对象却是空的。这就是ThreadLocal的线程隔离性。
public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); }
ThreadLocalMap getMap(Thread t) { return t.threadLocals; }
t.threadLocals是每个线程里面的全局变量。我们不用看set里面代码具体做了什么。我们大致可以看出来,他是从每个线程里面的threadLocals的key获取一个map。
应用spring的事务。在一个事务中,假设有2个方法,对应着有2个Connection,因为事务是要保证要么都成功,要么就失败。所以Connection肯定要保证同一个。但是Connection都是从连接池中注入的,怎么保证相同的呢。
这时候就是ThreadLocal起作用了,可以在第一个连接从连接池注入的时候,就把这个连接对象放到ThreadLocal中,之后的连接直接从这里面拿,这样就能保证一个线程的Conncetion是同一个了。
但有时候会有疑问,为什么不用传参,传参也能够导致一个对象一致性。其实传参也是可以的,但是方法调用过多的时候,那时候参数一层套一层,太过累赘。也可以使用静态变量来保证,但是会造成整个上下文的污染,本来能线程
中解决的,干嘛要用全局变量来呢。
2.ThreadLocal为什么要设置成弱引用
首先是static ThreadLocal<People> t1 = new ThreadLocal<>()一个强引用。然后在ThreadLocal对象中set值的时候

我们又可以看到一个当前线程的一个Map:threadLocals对象又指向了ThreadLocal引用。如果这个map指向是个强引用怎么办,我们就算把t1=null,这个ThreadLocal还是不能被垃圾回收了。如果这个编程弱引用,那么当t1置为null后,这个ThreadLocal就可以被垃圾回收了。
private void set(ThreadLocal<?> key, Object value) { // We don't use a fast path as with get() because it is at // least as common to use set() to create new entries as // it is to replace existing ones, in which case, a fast // path would fail more often than not. Entry[] tab = table; int len = tab.length; int i = key.threadLocalHashCode & (len-1); for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) { ThreadLocal<?> k = e.get(); if (k == key) { e.value = value; return; } if (k == null) { replaceStaleEntry(key, value, i); return; } } tab[i] = new Entry(key, value); int sz = ++size; if (!cleanSomeSlots(i, sz) && sz >= threshold) rehash(); }
static class Entry extends WeakReference<ThreadLocal<?>> { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal<?> k, Object v) { super(k); value = v; } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix