ThreadLocal源码解析

ThreadLocal为每个线程提供独立的局部变量副本,避免多线程同步,实现线程封闭。其内部通过ThreadLocalMap存储,使用弱引用作为Key,减少内存泄漏风险。initialValue()方法用于设置初始值,get()和set()方法则用于读写线程局部变量。
摘要由CSDN通过智能技术生成
* This class provides thread-local variables.These variables differ from
* their normal counterparts in that each thread that accesses one (via its
* {@code get} or {@code set} method) has its own, independently initialized
* copy of the variable.{@code ThreadLocal} instances are typically private
* static fields in classes that wish to associate state with a thread (e.g.,
* a user ID or Transaction ID).

ThreadLocal类用来提供线程内部的局部变量。这种变量在多线程环境下访问(通过get或set方法访问)时能保证各个线程里的变量相对独立于其他线程内的变量。ThreadLocal实例通常来说都是private static类型的,用于关联线程和线程的上下文。

ThreadLocal的作用是提供线程内的局部变量,这种变量在线程的生命周期内起作用,减少同一个线程内多个函数或者组件之间一些公共变量的传递的复杂度ThreadLocal不是同步机制,也不解决共享对象的多线程竞态条件问题。

ThreadLocal用来辅助平衡效率与线程的资源分配。

ThreadLocal会为每一个线程提供一个独立的变量副本,从而隔离了多个线程对数据的并发访问冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。

对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,ThreadLocal采用了“以空间换时间”的方式。同步机制仅提供一份变量,让不同的线程排队访问,ThreadLocal为每一个线程都提供了一份变量, 因此可以同时访问而互不影响。如果仅在单线程内访问数据,就不需要同步,这种技术被称为线程封闭(Thread Confinement)。Java语言及其核心库提供了一些机制来帮助维持线程封闭性,例如ThreadLocal类。

ThreadLocal

public void set(T value) {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null)map.set(this, value);elsecreateMap(t, value);
}

get():当某个线程初次调用ThreadLocal.get方法时,就会调用**initialValue()**来获取初始值,否则返回由当前执行线程在调用set(T)的最新值,该方法避免了将这个对象作为参数传递的麻烦。

public T get() {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null) {ThreadLocalMap.Entry e = map.getEntry(this);if (e != null) {@SuppressWarnings("unchecked")T result = (T)e.value;return result;}}return setInitialValue();
}

(1)获取当前线程(2)根据当前线程获取一个map

(3)如果获取的map不为空,则在map中以ThreadLocal的引用作为key来在map中获取对应的value e,否则转到(5)

(4)如果e不为null,则返回e.value,否则转到(5)

(5)Map为空或者e为空,则通过initialValue函数获取初始值value,然后用ThreadLocal的引用和value作为firstKey和firstValue创建一个新的Mapremove():将当前线程的ThreadLocal绑定的值删除

public void remove() {ThreadLocalMap m = getMap(Thread.currentThread());if (m != null)m.remove(this);
}

initialValue():用于设置 ThreadLocal 的初始值,默认返回 null,该函数是protected类型的,通常该函数都会以匿名内部类的形式被重载,以指定初始值

protected T initialValue() {return null;
}

getMap(Thread):获取线程的ThreadLocalMap

ThreadLocalMap getMap(Thread t) {return t.threadLocals;
}

createMap(Thread,T):初始化线程的threadLocals,然后设定key-value

void createMap(Thread t, T firstValue) {t.threadLocals = new ThreadLocalMap(this, firstValue);
}

createInheritedMap(ThreadLocalMap):

static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) {return new ThreadLocalMap(parentMap);
}

nextHashCode():

private static int nextHashCode() {return nextHashCode.getAndAdd(HASH_INCREMENT);
}

setInitialValue():```
private T setInitialValue() {T value = initialValue();Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null)map.set(this, value);elsecreateMap(t, value);return value;
}


1.每个Map的Entry数量变小了:之前是Thread的数量,现在是ThreadLocal的数量,能提高性能2.当Thread销毁之后对应的ThreadLocalMap也就随之销毁了,能减少内存使用量<img src="https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2018/3/3/161eb0136425b246~tplv-t2oaga2asx-zoom-in-crop-mark:4536:0:0:0.image)每个线程中都有一个自己的ThreadLocalMap类对象,可以将线程自己的对象保持到其中,各管各的,线程可以正确的访问到自己的对象" style="margin: auto" />

java.lang.Thread:

ThreadLocal.ThreadLocalMap threadLocals = null;
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;


<img src="https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2018/3/3/161ea8de0add4875~tplv-t2oaga2asx-zoom-in-crop-mark:4536:0:0:0.image)``" style="margin: auto" />
static class Entry extends WeakReference<ThreadLocal<?>> {/** The value associated with this ThreadLocal. */Object value;Entry(ThreadLocal<?> k, Object v) {super(k);value = v;}
}

ThreadLocalMap是使用ThreadLocal的弱引用作为Key的。保存在Thread中,当线程终止后,这些值会作为垃圾回收

private static ThreadLocal integerThreadLocal = new ThreadLocal<>(); private static InheritableThreadLocal inheritableThreadLocal =new InheritableThreadLocal<>();

@Test
public void inheritableThreadLocal() {// 父线程integerThreadLocal.set(1);inheritableThreadLocal.set(1);//结果:pool-1-thread-1:null/1threadFactory.newThread(() -> System.out.println(Thread.currentThread().getName() + “:”+ integerThreadLocal.get() + “/”+ inheritableThreadLocal.get())).start();
}


**Reference(引用)**

<img src="https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2018/3/3/161ebaf6acc1e025~tplv-t2oaga2asx-zoom-in-crop-mark:4536:0:0:0.image)* 强引用(FinalReference、Finalizer )类似“Object obj =new Object()”这类的引用,只要强引用还存在,垃圾收集器永远不会回收掉被引用的对象。强引用是Java的默认引用实现, 它会尽可能长时间的存活于JVM内, 当没有任何对象指向它时, GC执行后也不会被回收。如果一个对象具有强引用,那就类似于必不可少的生活用品, 垃圾回收器绝不会回收它。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误, 使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足问题。JVM 系统采用 **Finalizer** 来管理每个**强引用对象** , 并将其被标记要清理时加入 **ReferenceQueue**, 并逐一调用该对象的 **finalize()** 方" style="margin: auto" />

Object obj = new Object();
Object strongReference = obj;
Assertions.assertSame(obj, strongReference);
obj = null;
System.gc();
Assertions.assertNull(obj);
Assertions.assertNotNull(strongReference);


<img src="https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2018/3/3/161ec089ec8d396a~tplv-t2oaga2asx-zoom-in-crop-mark:4536:0:0:0.image)Finalizer是FinalReference的子类,该类被final修饰,不可再被继承,JVM实际操作的是Finalizer。当一个类满足实例化FinalReference的条件时,JVM会调用Finalizer.register()进行注册。* 软引用(java.lang.ref.SoftReference)用来描述一些还有用,但并非必需的对象。对于软引用关联着的对象,在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围之中并进行第二次回收。如果这次回收还是没有足够的内存,才会抛出内存溢出异常。SoftReference 于 WeakReference 的特性基本一致,最大的区别在于 SoftReference 会尽可能长的保留引用直到 JVM 内存不足时才会被回收(虚拟机保证),这一特性使得SoftReference非常适合缓存应" style="margin: auto" />

Object obj = new Object();
SoftReference softReference = new SoftReference<>(obj);
Assertions.assertNotNull(softReference.get());
obj = null;
System.gc();
Assertions.assertNull(obj);
// SoftReference 只有在 jvm OutOfMemory 之前才会被回收, 所以它非常适合缓存应用
Assertions.assertNotNull(softReference.get());


* 弱引用(java.lang.ref.WeakReference)<img src="https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2018/3/3/161eb69ea4d9a85f~tplv-t2oaga2asx-zoom-in-crop-mark:4536:0:0:0.image)用来描述非必须对象的,但它的强度比软引用要弱一些,被弱引用关联的对象只能生存到下一次垃圾收集发生之前。当垃圾收集器工作时,无论当前内存是否足够,都会回收掉只被弱引用关联的对象" style="margin: auto" />

Object obj = new Object();
WeakReference weakReference = new WeakReference<>(obj);
Assertions.assertSame(obj, weakReference.get());
obj = null;
System.gc();
Assertions.assertNull(weakReference.get());

Map<Object, Object> weakHashMap = new WeakHashMap<>();
Object key = new Object();
Object value = new Object();
weakHashMap.put(key, value);
Assertions.assertTrue(weakHashMap.containsValue(value));
key = null;
System.gc();
Thread.sleep(1000);
// 一旦没有指向 key 的强引用, WeakHashMap 在 GC 后将自动删除相关的 entry
Assertions.assertFalse(weakHashMap.containsValue(value));


* 虚引用(java.lang.ref.PhantomReference)称为幽灵引用或者幻影引用,是最弱的一种引用关系。一个对象是否有虚引用的存在,完全不会对其生存时间构成影响,也无法通过虚引用来取得一个对象实例。为一个对象设置虚引用关联的唯一目的就是希望能在这个对象被收集器回收时收到一个系统通知。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值