Java线程本地存储ThreadLocal

匿名 (未验证) 提交于 2019-12-02 21:52:03

前言

  • 无同步
  • Thread-Specific Storage没有共享资源
  • ThreadLocal

ThreadLocal 思维导图

线程安全 示意图

1. 用法

ThreadLocalThreadLocalandroid.os.Looper.javaThreadLocal

ThradlLocal UML类图

// /frameworks/base/core/java/android/os/Looper.java  public class Looper {      // ...      // sThreadLocal.get() will return null unless you've called prepare().     static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();      private static void prepare(boolean quitAllowed) {         if (sThreadLocal.get() != null) {             throw new RuntimeException("Only one Looper may be created per thread");         }         // 设置线程局部变量的值         sThreadLocal.set(new Looper(quitAllowed));     }      public static Looper myLooper() {         // 获取线程局部变量的值         return sThreadLocal.get();     }      public static void prepare() {         prepare(true);     }      // ... }
  • ThreadLocalstatic final变量LooperLooper
  • Looper#prepare()ThreadLocal#set()设置
  • Looper#myLooper()ThreadLocal#get()获取

Timethreadsͼ - 01

  • 重写ThreadLocal#initialValue()

    public ConcurrentHashMap() {     this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL); } public ConcurrentHashMap(int initialCapacity,                              float loadFactor, int concurrencyLevel) {     if (!(loadFactor > 0) || initialCapacity < 0 || concurrencyLevel <= 0)         throw new IllegalArgumentException();     if (concurrencyLevel > MAX_SEGMENTS)         concurrencyLevel = MAX_SEGMENTS;     // Find power-of-two sizes best matching arguments     int sshift = 0;     int ssize = 1;     while (ssize < concurrencyLevel) {         ++sshift;         ssize <<= 1;     }     this.segmentShift = 32 - sshift;//用于高位,判断落在哪个Segment     this.segmentMask = ssize - 1;//用于取模。之前在hashmap的indexFor方法有提过。2的n次方-1     if (initialCapacity > MAXIMUM_CAPACITY)         initialCapacity = MAXIMUM_CAPACITY;     int c = initialCapacity / ssize;     if (c * ssize < initialCapacity)         ++c;     int cap = MIN_SEGMENT_TABLE_CAPACITY;     while (cap < c)         cap <<= 1;     // create segments and segments[0]     Segment<K,V> s0 =         new Segment<K,V>(loadFactor, (int)(cap * loadFactor),                          (HashEntry<K,V>[])new HashEntry[cap]);//初始化第一个位置的Segment     Segment<K,V>[] ss = (Segment<K,V>[])new Segment[ssize];//初始化Segments     UNSAFE.putOrderedObject(ss, SBASE, s0); // ordered write of segments[0]     this.segments = ss; }
    • ThreadLocal#get()ThreadLocal#setInitialValue()
    • 懒初始化get()
    • 默认null
  • ThreadLocal#remove()移除ThreadLocal#get()set()ThreadLocal#setInitialValue()

ThreadLocal

ThreadLocal生命周期 示意图

2. 编程规约

ThreadLocal

  • SimpleDateFormatestaticDateUtils

    正例:

    private static final ThreadLocal<DataFormat> df = new ThreadLocal<DateFormat>(){       @Override       protected DateFormat initialValue(){               return new SimpleDateFormat("yyyy-MM-dd");       } };

    InstantDateLocalDateTimeCalendarDateTimeFormatterSimpleDateFormat

  • ThreadLocalstatic

    ThreadLocalstatic

ThreadLocalThreadLocal

Segment

ConcurrentHashMap是由多个Segment组成的,Segment继承了ReentrantLock,每次加锁都是对某个Segment,不会影响其他Segment,达到了锁分离(也叫分段锁)的作用。

每个Segment又包含了HashEntry数组,HashEntry是一个链表。如下图所示:

concurrencyLevel:并发数,默认16,直接影响segmentShift和segmentMask的值,以及Segment的初始化数量。Segment初始化的数量,为最接近且大于的办等于2的N次方的值,比如concurrencyLevel=16,Segment数量为16,concurrencyLevel=17,Segment数量为32。segmentShift的值是这样的,比如Segment是32,相对于2的5次方,那么他的值就是32-5,为27,后面无符号右移27位,也就是取高5位的时候,就是0到31的值,此时Segment的下标也是0到31,取模后对应着每个Segment。segmentMask就是2的n次方-1,这边n是5,用于取模。之前在hashmap的indexFor方法有提过。

文章来源: https://www.cnblogs.com/aishangJava/p/11267562.html
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!