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

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

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

这里并不必要思量 ThreadLocalMap 的线程安详题目。由于每个线程有且只有一个 ThreadLocalMap 工具,而且只有该线程本身可以会见它,其余线程不会会见该 ThreadLocalMap,也即该工具不会在多个线程中共享,也就不存在线程安详的题目。

4. 配置实例

除了通过initialValue()要领配置实例的初始值,还可通过 set 要领配置线程内实例的值,如下所示。

  1. public void set(T value) { 
  2.   Thread t = Thread.currentThread(); 
  3.   ThreadLocalMap map = getMap(t); 
  4.   if (map != null) 
  5.     map.set(this, value); 
  6.   else 
  7.     createMap(t, value); 

该要领先获取该线程的 ThreadLocalMap 工具,然后直接将 ThreadLocal 工具(即代码中的 this)与方针实例的映射添加进 ThreadLocalMap 中。虽然,假如映射已经存在,就直接包围。其它,假如获取到的 ThreadLocalMap 为 null,则先建设该 ThreadLocalMap 工具。

5. 防备内存走漏

对付已经不再被行使且已被接纳的 ThreadLocal 工具,它在每个线程内对应的实例因为被线程的 ThreadLocalMap 的 Entry 强引用,无法被接纳,也许会造成内存走漏。

针对该题目,ThreadLocalMap 的 set 要领中,通过 replaceStaleEntry 要领将全部键为 null 的 Entry 的值配置为 null,从而使得该值可被接纳。其它,会在 rehash 要领中通过 expungeStaleEntry 要领将键和值为 null 的 Entry 配置为 null 从而使得该 Entry 可被接纳。通过这种方法,ThreadLocal 可防备内存走漏。

  1. private void set(ThreadLocal<?> key, Object value) { 
  2.   Entry[] tab = table; 
  3.   int len = tab.length; 
  4.   int i = key.threadLocalHashCode & (len-1); 
  5.   for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) { 
  6.     ThreadLocal<?> k = e.get(); 
  7.     if (k == key) { 
  8.       e.value = value; 
  9.       return; 
  10.     } 
  11.     if (k == null) { 
  12.       replaceStaleEntry(key, value, i); 
  13.       return; 
  14.     } 
  15.   } 
  16.   tab[i] = new Entry(key, value); 
  17.   int sz = ++size; 
  18.   if (!cleanSomeSlots(i, sz) && sz >= threshold) 
  19.     rehash(); 

五、合用场景

如上文所述,ThreadLocal 合用于如下两种场景

  • 每个线程必要有本身单独的实例
  • 实例必要在多个要领中共享,但不但愿被多线程共享

对付第一点,每个线程拥有本身实例,实现它的方法许多。譬喻可以在线程内部构建一个单独的实例。ThreadLoca 可以以很是利便的情势满意该需求。

对付第二点,可以在满意第一点(每个线程有本身的实例)的前提下,通过要领间引用转达的情势实现。ThreadLocal 使得代码耦合度更低,且实现更优雅。

六、案例

对付 Java Web 应用而言,Session 生涯了许多信息。许多时辰必要通过 Session 获守信息,有些时辰又必要修改 Session 的信息。一方面,必要担保每个线程有本身单独的 Session 实例。另一方面,因为许多处所都必要操纵 Session,存在多要领共享 Session 的需求。假如不行使 ThreadLocal,可以在每个线程内构建一个 Session实例,并将该实例在多个要领间转达,如下所示。

  1. public class SessionHandler { 
  2.   @Data 
  3.   public static class Session { 
  4.     private String id; 
  5.     private String user; 
  6.     private String status; 
  7.   } 
  8.   public Session createSession() { 
  9.     return new Session(); 
  10.   } 
  11.   public String getUser(Session session) { 
  12.     return session.getUser(); 
  13.   } 
  14.   public String getStatus(Session session) { 
  15.     return session.getStatus(); 
  16.   } 
  17.   public void setStatus(Session session, String status) { 
  18.     session.setStatus(status); 
  19.   } 
  20.   public static void main(String[] args) { 
  21.     new Thread(() -> { 
  22.       SessionHandler handler = new SessionHandler(); 
  23.       Session session = handler.createSession(); 
  24.       handler.getStatus(session); 
  25.       handler.getUser(session); 
  26.       handler.setStatus(session, "close"); 
  27.       handler.getStatus(session); 
  28.     }).start(); 
  29.   } 

该要领是可以实现需求的。可是每个必要行使 Session 的处所,都必要显式转达 Session 工具,要领间耦合度较高。

(编辑:湖南网)

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

热点阅读