加入收藏 | 设为首页 | 会员中心 | 我要投稿 湖南网 (https://www.hunanwang.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 教程 > 正文

正确领略Thread Local的道理与合用场景

发布时间:2018-08-17 13:17:49 所属栏目:教程 来源:郭俊
导读:技能沙龙 | 邀您于8月25日与国美/AWS/转转三位专家配合切磋小措施电商拭魅战 一、ThreadLocal办理什么题目 因为 ThreadLocal 支持范型,如 ThreadLocal StringBuilder ,为表述利便,后文用 变量 代表 ThreadLocal 自己,而用 实例 代表详细范例(如 StringBui

上述方案中,呈现锁的题目,缘故起因在于多线程会见统一个 Map。假如该 Map 由 Thread 维护,从而使得每个 Thread 只会见本身的 Map,那就不存在多线程写的题目,也就不必要锁。该方案如下图所示。

ThreadLocal side Map

该方案固然没有锁的题目,可是因为每个线程会见某 ThreadLocal 变量后,城市在本身的 Map 内维护该 ThreadLocal 变量与详细实例的映射,假如不删除这些引用(映射),则这些 ThreadLocal 不能被接纳,也许会造成内存走漏。后文会先容 JDK 怎样办理该题目。

四、ThreadLocal 在 JDK 8 中的实现

1. ThreadLocalMap与内存走漏

该方案中,Map 由 ThreadLocal 类的静态内部类 ThreadLocalMap 提供。该类的实例维护某个 ThreadLocal 与详细实例的映射。与 HashMap 差异的是,ThreadLocalMap 的每个 Entry 都是一个对 键 的弱引用,这一点从super(k)可看出。其它,每个 Entry 都包括了一个对 值 的强引用。

  1. static class Entry extends WeakReference<ThreadLocal<?>> { 
  2.   /** The value associated with this ThreadLocal. */ 
  3.   Object value; 
  4.   Entry(ThreadLocal<?> k, Object v) { 
  5.     super(k); 
  6.     vvalue = v; 
  7.   } 

行使弱引用的缘故起因在于,当没有强引用指向 ThreadLocal 变量时,它可被接纳,从而停止上文所述 ThreadLocal 不能被接纳而造成的内存走漏的题目。

可是,这里又也许呈现其它一种内存走漏的题目。ThreadLocalMap 维护 ThreadLocal 变量与详细实例的映射,当 ThreadLocal 变量被接纳后,该映射的键变为 null,该 Entry 无法被移除。从而使得实例被该 Entry 引用而无法被接纳造成内存走漏。

注:Entry固然是弱引用,但它是 ThreadLocal 范例的弱引用(也即上文所述它是对 键 的弱引用),而非详细实例的的弱引用,以是无法停止详细实例相干的内存走漏。

2. 读取实例

读取实例要领如下所示

  1. public T get() { 
  2.   Thread t = Thread.currentThread(); 
  3.   ThreadLocalMap map = getMap(t); 
  4.   if (map != null) { 
  5.     ThreadLocalMap.Entry e = map.getEntry(this); 
  6.     if (e != null) { 
  7.       @SuppressWarnings("unchecked") 
  8.       T result = (T)e.value; 
  9.       return result; 
  10.     } 
  11.   } 
  12.   return setInitialValue(); 

读取实例时,线程起首通过getMap(t)要领获取自身的 ThreadLocalMap。从如下该要领的界说可见,该 ThreadLocalMap 的实例是 Thread 类的一个字段,即由 Thread 维护 ThreadLocal 工具与详细实例的映射,这一点与上文说明同等。

  1. ThreadLocalMap getMap(Thread t) { 
  2.   return t.threadLocals; 

获取到 ThreadLocalMap 后,通过map.getEntry(this)要领获取该 ThreadLocal 在当前列程的 ThreadLocalMap 中对应的 Entry。该要领中的 this 即当前会见的 ThreadLocal 工具。

假如获取到的 Entry 不为 null,从 Entry 中取出值即为所需会见的本线程对应的实例。假如获取到的 Entry 为 null,则通过setInitialValue()要领配置该 ThreadLocal 变量在该线程中对应的详细实例的初始值。

3. 配置初始值

配置初始值要领如下

  1. private T setInitialValue() { 
  2.   T value = initialValue(); 
  3.   Thread t = Thread.currentThread(); 
  4.   ThreadLocalMap map = getMap(t); 
  5.   if (map != null) 
  6.     map.set(this, value); 
  7.   else 
  8.     createMap(t, value); 
  9.   return value; 

该要领为 private 要领,无法被重载。

起首,通过initialValue()要领获取初始值。该要领为 public 要领,且默认返回 null。以是典范用法中经常重载该要领。上例中即在内部匿名类中将其重载。

(编辑:湖南网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读