1. ThreadLocal简介
a. ThreadLocal是什么?
ThreadLocal叫做线程变量,意思是ThreadLocal中填充的变量属于当前线程,该变量对其他线程而言是隔离的,也就是说该变量是当前线程独有的变量。ThreadLocal为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量。
b. ThreadLocal的作用
因为每一个Thread内有自己的实例副本,且该副本只能由当前Thread使用。这意味着不存在多线程间共享的问题。通常情况下,ThreadLocal变量会被private static修饰。
c. 为什么要使用ThreadLocal?
总的来说,ThreadLocal适用于每个线程需要自己独立的实例,且该实例需要在多个方法中被使用的情况,也就是变量在线程间隔离而在方法或类间共享的场景。
2. ThreadLocal和Synchronized的区别
a. 相同点
ThreadLocal和Synchronized都用于解决多线程并发访问问题。
b. 不同点
Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离。Synchronized是利用锁的机制,使变量或代码块在某一时刻只能被一个线程访问。ThreadLocal为每一个线程都提供了变量的副本,使得每个线程在某一时间访问到的并不是同一个对象,从而隔离了多个线程对数据的共享。而Synchronized正好相反,它用于在多个线程间通信时能够获得数据共享。
c. 简单理解ThreadLocal
一句话理解ThreadLocal:ThreadLocal是作为当前线程中属性ThreadLocalMap集合中的某一个Entry的key值(Entry(ThreadLocal, value))。虽然不同的线程之间ThreadLocal这个key值是一样的,但是不同的线程所拥有的ThreadLocalMap是独一无二的,也就是不同的线程间同一个ThreadLocal(key)对应存储的值(value)不一样,从而达到了线程间变量隔离的目的,但是在同一个线程中这个value变量地址是一样的。
3. ThreadLocal原理
public void set(T value) {
//1.获取当前线程
Thread t = Thread.currentThread();
//2.获取线程中的属性threadLocalMap,如果threadLocalMap不为空,
//则直接更新要保存的变量值,否则创建threadLocalMap,并赋值
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
// 初始化threadLocalMap 并赋值
createMap(t, value);
}
static class ThreadLocalMap {
/**
* The entries in this hash map extend WeakReference, using
* its main ref field as the key (which is always a
* ThreadLocal object). Note that null keys (i.e. entry.get()
* == null) mean that the key is no longer referenced, so the
* entry can be expunged from table. Such entries are referred to
* as "stale entries" in the code that follows.
*/
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
}
public T get() {
//1、获取当前线程
Thread t = Thread.currentThread();
//2、获取当前线程的ThreadLocalMap
ThreadLocalMap map = getMap(t);
//3、如果map数据不为空,
if (map != null) {
//3.1、获取threadLocalMap中存储的值
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
//如果数据为null,则初始化,
//初始化的结果,ThreadLocalMap中存放key值为ThreadLocal,值为null
return setInitialValue();
}
private T setInitialValue() {
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
return value;
}
public void remove() {
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
m.remove(this);
}
ThreadLocal的实现原理是通过在每个线程中维护一个ThreadLocalMap,其中保存了ThreadLocal作为key和对应的值value。当调用ThreadLocal的set方法时,它会首先获取当前线程,然后从当前线程的ThreadLocalMap中查找是否已经有对应的Entry,如果有,则直接更新值,如果没有,则创建新的Entry并放入ThreadLocalMap中。而调用get方法时,也是首先获取当前线程,然后从ThreadLocalMap中获取对应的值。这种方式保证了每个线程对ThreadLocal的操作都是独立的,不会影响其他线程的值。
4. ThreadLocal与Thread、ThreadLocalMap之间的关系
ThreadLocalMap实际上是Thread线程的一个属性值,而ThreadLocal是维护ThreadLocalMap的工具类。Thread线程可以拥有多个ThreadLocal维护的线程独享的共享变量,每个ThreadLocal对应一个变量。
5. ThreadLocal常见使用场景
a. 每个线程需要有自己单独的实例
b. 实例需要在多个方法中共享,但不希望被多线程共享
ThreadLocal是解决多线程并发访问问题的重要工具之一,特别适用于需要在线程间隔离而在方法或类间共享的场景。通过ThreadLocal,我们可以轻松地实现每个线程拥有自己独立的变量,避免了多线程共享数据的问题,提高了程序的性能和可维护性。希望这篇文章对你理解ThreadLocal有所帮助。