Foreword
- ThreadLocal is a non-synchronous thread-safe implementation
- It reflects the
Thread-Specific Storage
pattern: even if only one entrance, the interior will be allocated for each thread-specific storage space, the threads do not share resources - This paper will summarize
ThreadLocal
the usage and implementation details, I hope I could help
ThreadLocal mind map
Thread Security Diagrams
1. Usage
ThreadLocal
Was easy to use, ThreadLocal
it offers the following public and protected method, this article will refer to android.os.Looper.java as an example to explain the ThreadLocal
usage:
ThradlLocal UML class diagram
// /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); } // ... }
ThreadLocal
Is a static final variable , is a generic parameterLooper
, acceptance ofLooper
the value of the typeLooper#prepare()
CallingThreadLocal#set()
set the value of the variable's value without disturbing each other, a different set of threads, not overwrite each otherLooper#myLooper()
CallingThreadLocal#get()
acquisition value of a variable, the value of non-interfering get different threads
Timethreads图 - 01
-
Subclass rewrite
ThreadLocal#initialValue()
, you can set the variable initial values, we view the source code: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; // a high level, which is determined to fall Segment this.segmentMask = ssize The - . 1; // for modulo. Before indexFor method hashmap are mentioned. N-th power of -12 IF (initialCapacity> MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY; int = initialCapacity C / ssize The; IF (ssize The C * <initialCapacity) ++ C; int = MIN_SEGMENT_TABLE_CAPACITY CAP; the while (CAP <C) << CAP = . 1; // Create Segments and Segments [0] Segment <K, V> S0 = new new Segment <K, V> (loadFactor, ( int) (* loadFactor CAP), (HashEntry <K, V> []) new new HashEntry [CAP]); // initialize the first position Segment Segment <K, V> [] = SS (Segment <K, V> []) new new Segment [ssize the]; // initialize Segments UNSAFE.putOrderedObject (ss , SBASE,// ordered write of segments[0] this.segments = ss; }
- In
ThreadLocal#get()
trying to get the value of variables, it will be called if an emptyThreadLocal#setInitialValue()
setting the initial value - Lazy Initialization : until the first call
get()
will be to set the initial value - Default : initial value is set null
- In
-
ThreadLocal#remove()
For removing the value previously stored variables. If the current thread next callThreadLocal#get()
time, noset()
new values will still useThreadLocal#setInitialValue()
set the initial value.
Here we can sum up ThreadLocal
the life cycle, as shown below:
ThreadLocal diagram of the life cycle
2. Programming Statute
remember? "Ali Baba Java Development Manual" mentioned about the ThreadLocal
programming of the Statute, as follows:
-
5. [mandatory]
SimpleDateFormate
is not thread-safe class, usually not defined as a static variable, if defined as static, it must be locked, or the use ofDateUtils
toolsPositive examples:
private static final ThreadLocal<DataFormat> df = new ThreadLocal<DateFormat>(){ @Override protected DateFormat initialValue(){ return new SimpleDateFormat("yyyy-MM-dd"); } };
Description: If an application is JDK8, may be used
Instant
instead ofDate
,LocalDateTime
instead ofCalendar
,DateTimeFormatter
instead ofSimpleDateFormat
, official explanation given: simple beautiful strong immutable thread-safe . -
15. [Reference] (the original is too long-winded, the following is the author paraphrased)
ThreadLocal
variable recommends using static modification, can guarantee to create variable initialization in the class, all class instances share the same static variable.Noticed? In the beginning of the article Looper.java source, the
ThreadLocal
variable is the use ofstatic
modified
See here, I believe you have mastered the ThreadLocal
usage, the next article will delve ThreadLocal
inside to explore the implementation details of the data structure.
Segment
ConcurrentHashMap is composed of a plurality of Segment, Segment inherited ReentrantLock, every lock is on a Segment, it will not affect other Segment, to achieve the separation lock (also known as sub-lock) role.
Each Segment also contains the HashEntry array, HashEntry is a linked list. As shown below:
concurrencyLevel: concurrent, default 16, a direct impact on the value of segmentShift and segmentMask, and the number of initialization Segment. Segment number of initialization, and larger than the run closest to the value equal to N-th power of 2, such concurrencyLevel = 16, the number of Segment 16, concurrencyLevel = 17, the number of Segment 32. SegmentShift value is such that, for example Segment 32, 5 with respect to the power of 2, then his value is 32-5, for the time 27, 27 behind the unsigned right shift, which is to take the upper 5 bits, is value of 0 to 31, subscript Segment case is 0 to 31, the modulus corresponding to each Segment. 2 is the power of n segmentMask -1, here n is 5, a modulo. Before indexFor method hashmap are mentioned.