ThreadLocal
早期设计
早期设计的问题
其拥有者为ThreadLocal,每一个ThreadLoca1实例,拥有一个Map实例。
问题1:浪费空间
如果线程数量多,则ThreadLocalMap存储”Key-Value” entry的数量也多。一般情况下,程序的ThreadLoca 1实例会比较少,而线程数较多,所以,这种涉及方案,比较浪费空间。
问题2:存活周期太长
在Thread (线程)实例销毁后,ThreadLoca 1实例内部的Th readLoca lMap还是存在的。ThreadLocal本来是给Thread 做线程隔离用的,现在Thread 不需要隔离了,但是ThreadLocal还在。
JDK1.8的ThreadLocal
现在ThreadLocalMap的归属是线程了,由线程去持有ThreadLocal变量
import java.util.concurrent.atomic.AtomicInteger;public class ThreadId {// Atomic integer containing the next thread ID to be assignedprivate static final AtomicInteger nextId = new AtomicInteger(0);// Thread local variable containing each thread's IDprivate static final ThreadLocal<Integer> threadId =new ThreadLocal<Integer>() {@Override protected Integer initialValue() {return nextId.getAndIncrement();}};// Returns the current thread's unique ID, assigning it if necessarypublic static int get() {return threadId.get();}}
- 本质上,ThreadLocal是通过空间来换取时间,从而实现每个线程当中都会有一个变量的副本,这样每个线程就都会操作该副本,从而完全规避了多线程的并发问题,不再需要同步变量。
- ThreadLocal的实例要声明为static类型,表示全局的含义,使当前类所有实例都可以访问到这个ThreadLocal变量。
public static void main(String[] args) {ThreadLocal<String> threadLocal = new ThreadLocal();threadLocal.set("hello world");System.out.println(threadLocal.get());threadLocal.set("welcome");System.out.println(threadLocal.get());}
ThreadLocal.get()
Thread类里面的threadLocals
ThreadLocal.ThreadLocalMap threadLocals = null;
Thread类里面有一个**ThreadLocalMap类型的成员变量 threadLocals**
ThreadLocalMap与Entry
- ThreadLocalMap 是 ThreadLocal 的内部类
- Entry 是 ThreadLocalMap的内部类
:::tips
Entry的key是ThreadLocal,值是我们要存的对象。
可以发现,这个对象并不是存储在ThreadLocal的对象中,而是将T**h**readLocal实例作为key,目标Object作为value,存储到Entry中,然后存储到当前线程的threadLocals里面!
:::
ThreadLocal与Synchonized的比较
ThreadLocal和Synchonized都用于解决多线程并发访问。
- synchronized是利用锁的机制,使变量或代码块在某一时该仅仅能被一个线程访问。
- ThreadLocal为每个线程都提供了变量的副本,使得每个线程在某一时间访问到的并非同一个对象,这样就隔离了多个线程对数据的数据共享。


