CAS CAS (Compare-And-Swap),是CPU并发原语
在Java中:
调用UnSafe类中的CAS 方法,JVM会实现出CAS汇编指令,这是一种完全依赖于硬件的功能,实现了原子操作 CAS作用:
比较当前工作内存中的值和主物理内存中的值,如果相同则执行规定操作 CAS特点:
CAS缺点:
Atomic 常用API 常见原子类:AtomicInteger、AtomicBoolean、AtomicLong
构造方法:
public AtomicInteger()
:初始化一个默认值为 0 的原子型 Integerpublic AtomicInteger(int initialValue)
:初始化一个指定值的原子型 Integer常用API:
方法 作用 public final int get()
获取 AtomicInteger 的值 public final int getAndIncrement()
以原子方式将当前值加 1,返回的是自增前的值 public final int incrementAndGet()
以原子方式将当前值加 1,返回的是自增后的值 public final int getAndSet(int value)
以原子方式设置为 new Value 的值,返回旧值 public final int addAndGet(int data)
以原子方式将输入的数值与实例中的值相加并返回 实例:AtomicInteger 里的 value
原理分析 AtomicInteger 原理 :
自旋锁+CAS算法(有3个操作数:内存值V, 旧的预期值A,要修改的值B)
getAndSet方法:
1 2 3 4 5 6 7 8 public final int getAndSet (int newValue) { return unsafe.getAndSetInt(this , valueOffset, newValue); }
1 2 3 4 5 6 7 8 9 10 11 public final int getAndSetInt (Object var1, long var2, int var4) { int var5; do { var5 = this .getIntVolatile(var1, var2); } while (!this .compareAndSwapInt(var1, var2, var5, var4)); return var5; }
getAndSet方法:
1 2 AtomicInteger a = new AtomicInteger ();a.getAndUpdate(i -> i + 10 );
1 2 3 4 5 6 7 8 public final int getAndUpdate (IntUnaryOperator updateFunction) { int prev, next; do { prev = get(); next = updateFunction.applyAsInt(prev); } while (!compareAndSet(prev, next)); return prev; }
compareAndSet方法:
1 2 3 4 5 6 7 8 9 public final boolean compareAndSet (int expect, int update) { return unsafe.compareAndSwapInt(this , valueOffset, expect, update); }
原子引用 对Object进行原子操作
原子引用类:AtomicReference
、AtomicStampedReference
、AtomicMarkableReference
AtomicReference类:
1 2 3 4 5 6 7 8 9 10 11 12 13 Student s1 = new Student (33 , "z3" );AtomicReference<Student> atomicReference = new AtomicReference <>(); atomicReference.set(s1); while (true ) { Student s2 = new Student (44 , "l4" ); if (atomicReference.compareAndSet(s1, s2)) { break ; } } System.out.println(atomicReference.get());
原子数组 原子数组类:AtomicIntegerArray
、AtomicLongArray
、AtomicReferenceArray
AtomicIntegerArray类方法:
1 2 3 public final boolean compareAndSet (int i, int expect, int update) { return compareAndSetRaw(checkedByteOffset(i), expect, update); }
原子更新器 原子更新器类:AtomicReferenceFieldUpdater
、AtomicIntegerFieldUpdater
、AtomicLongFieldUpdater
常用API:
static <U> AtomicIntegerFieldUpdater<U> newUpdater(Class<U> c, String fieldName)
:构造方法abstract boolean compareAndSet(T obj, int expect, int update)
:CAS方法1 2 3 4 5 AtomicIntegerFieldUpdater<Student> fieldUpdater = AtomicIntegerFieldUpdater.newUpdater(Student.class, "id" ); Student s1 = new Student (0 , "z3" );boolean b = fieldUpdater.compareAndSet(s1, 0 , 33 );
原子累加器 原子累加器类:LongAdder
、DoubleAdder
、LongAccumulator
、DoubleAccumulator
LongAdder和LongAccumulator区别:
相同点:都是CAS实现的 当accumulatorFunction等于null,初始值等于0时,LongAccumulator等于LongAdder 不同点:LongAdder是LongAccumulator的特例 LongAccumulator可以自定义累加规则,初始值 1 2 3 4 5 6 7 LongAdder longAdder = new LongAdder ();for (int i = 0 ; i < 1000 ; i++) { new Thread (() -> { longAdder.increment(); }).start(); }
1 2 3 4 5 6 7 8 LongAccumulator longAccumulator = new LongAccumulator ((left, right) -> left + right, 0 );for (int i = 0 ; i < 1000 ; i++) { new Thread (() -> { longAccumulator.accumulate(1 ); }).start(); }
Adder 优化机制 LongAdder是JDK8提供的类,跟AtomicLong有相同的效果,但对CAS机制进行了优化
分段CAS机制:
发生竞争时:创建Cell数组,将不同线程的操作离散到不同节点上(通过hash等算法映射) 设置多个累加单元,比如Thread-0累加Cell[0],Thread-1累加Cell[1]…最后将结果汇总 累加时操作不同的Cell变量,减少了CAS失败,从而提升了性能 自动分段迁移机制:
某个Cell的value执行CAS失败,自动寻找另一个Cell分段内的value值进行CAS 伪共享 Cell为累加的单元,是数组的形式
数组访问的索引是通过Thread里的threadLocalRandomProbe
域取模实现的(这个域是ThreadLocalRandom
更新的)
下面是Cell的部分代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @sun .misc.Contended static final class Cell { volatile long value; Cell(long x) { value = x; } final boolean cas (long cmp, long val) { return UNSAFE.compareAndSwapLong(this , valueOffset, cmp, val); } }
@sun.misc.Contended注解的作用:
Cell是数组的形式,在内存中是连续的。64位系统中,一个Cell为24字节(16字节的对象头,8字节的value)。一个cache line是64字节的,因此缓存可以存下两个Cell对象 。当Core-0要修改Cell[0],Core-1要修改Cell[1]时,无论谁成功都会导致当前缓存行失效,进而数据失效,需要从主存获取,影响效率
@sun.misc.Contended:在对象或字段的前后各增加128字节大小的padding,让CPU将对象预读至缓存时占用不同的缓存行 ,这样就不会造成对方缓存行的失效
源码解析 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 abstract class Striped64 extends Number { static final int NCPU = Runtime.getRuntime().availableProcessors(); transient volatile Cell[] cells; transient volatile long base; transient volatile int cellsBusy; }
工作流程:
cells占用内存大,所以是惰性加载的。如果无竞争,会直接累加base。 第一次竞争发生时,创建大小为2的cells数组,将当前base值包装为Cell对象,放入映射的槽位上 分段迁移后,还发生竞争时,扩容cells数组长度为原来的2倍,然后rehash。数组总长度是2的幂,默认为最大CPU数量(比如:6核心CPU最大为8槽位) 分段累加的过程中,如果当前线程对应的cells槽位为空,会新建Cell填充如果出现竞争,重新计算线程对应的槽位,继续自旋尝试修改 LongAdder#add方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 public void add (long x) { Cell[] as; long b, v; int m; Cell a; if ((as = cells) != null || !casBase(b = base, b + x)) { boolean uncontended = true ; if (as == null || (m = as.length - 1 ) < 0 || (a = as[getProbe() & m]) == null || !(uncontended = a.cas(v = a.value, v + x))) { longAccumulate(x, null , uncontended); } } }
1 2 3 4 final boolean casBase (long cmp, long val) { return UNSAFE.compareAndSwapLong(this , BASE, cmp, val); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 final void longAccumulate (long x, LongBinaryOperator fn, boolean wasUncontended) { int h; if ((h = getProbe()) == 0 ) { ThreadLocalRandom.current(); h = getProbe(); wasUncontended = true ; } boolean collide = false ; for (;;) { Cell[] as; Cell a; int n; long v; if ((as = cells) != null && (n = as.length) > 0 ) { if ((a = as[(n - 1 ) & h]) == null ) { if (cellsBusy == 0 ) { Cell r = new Cell (x); if (cellsBusy == 0 && casCellsBusy()) { boolean created = false ; try { Cell[] rs; int m, j; if ((rs = cells) != null && (m = rs.length) > 0 && rs[j = (m - 1 ) & h] == null ) { rs[j] = r; created = true ; } } finally { cellsBusy = 0 ; } if (created) break ; continue ; } } collide = false ; } else if (!wasUncontended) wasUncontended = true ; else if (a.cas(v = a.value, ((fn == null ) ? v + x : fn.applyAsLong(v, x)))) break ; else if (n >= NCPU || cells != as) collide = false ; else if (!collide) collide = true ; else if (cellsBusy == 0 && casCellsBusy()) { try { if (cells == as) { Cell[] rs = new Cell [n << 1 ]; for (int i = 0 ; i < n; ++i) rs[i] = as[i]; cells = rs; } } finally { cellsBusy = 0 ; } collide = false ; continue ; } h = advanceProbe(h); } else if (cellsBusy == 0 && cells == as && casCellsBusy()) { boolean init = false ; try { if (cells == as) { Cell[] rs = new Cell [2 ]; rs[h & 1 ] = new Cell (x); cells = rs; init = true ; } } finally { cellsBusy = 0 ; } if (init) break ; } else if (casBase(v = base, ((fn == null ) ? v + x : fn.applyAsLong(v, x)))) break ; } }
LongAdder#sum方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 public long sum () { Cell[] as = cells; Cell a; long sum = base; if (as != null ) { for (int i = 0 ; i < as.length; ++i) { if ((a = as[i]) != null ) sum += a.value; } } return sum; }
ABA 什么是ABA问题:
(A)一个线程先读取共享内存数据值A,随后因某种原因,线程暂时挂起 (B)另一个线程临时将共享内存数据值先改为B,随后又改回为A (A)并通过CAS比较,最终比较结果将会无变化 解决方法,用版本号:
AtomicStampedReference
内部还维护了一个“状态戳”修改对象值得同时,也要修改状态戳 当AtomicStampedReference
设置对象值时,对象值以及状态戳都必须满足期望值,写入才会成功 1 2 3 4 5 6 7 while (true ) { int stamp = num.getStamp(); Integer expected = num.getReference(); if (num.compareAndSet(expected, expected + 100 , stamp, stamp + 1 )) { break ; } }
Unsafe Unsafe类是在sun.misc
包下,不属于Java标准。但是很多Java的基础类库,包括一些被广泛使用的高性能开发库都是基于Unsafe类开发的,比如Netty、Cassandra、Hadoop、Kafka等
Java中Unsafe类为我们提供类似C++手动管理内存的功能,同时也有了指针的问题
Unsafe类是final的,不能继承;构造函数是private的,因此无法在外部实例化
所有方法都是native的
1 2 3 4 5 6 public final class Unsafe { private static final Unsafe theUnsafe = new Unsafe (); private Unsafe () {} }
获取Unsafe 1 2 3 4 5 public Unsafe getUnsafe () throws IllegalAccessException { Field unsafeField = Unsafe.class.getDeclaredFields()[0 ]; unsafeField.setAccessible(true ); return (Unsafe) unsafeField.get(null ); }
CAS相关 1 2 3 4 5 public final boolean compareAndSwapObject (Object o, long offset, Object expected, Object x) public final boolean compareAndSwapInt (Object o, long offset, int expected, int x) public final boolean compareAndSwapLong (Object o, long offset, long expected, long x)
偏移量相关 1 2 3 4 5 public long staticFieldOffset (Field f) public long objectFieldOffset (Field f)
类加载 1 2 3 4 5 6 7 8 public Object allocateInstance (Class<?> cls) public boolean shouldBeInitialized (Class<?> c) public void ensureClassInitialized (Class<?> c)
defineClass
方法:定义一个类,用于动态地创建类。(JDK11被移除)defineAnonymousClass
方法:用于动态的创建一个匿名内部类。(JDK11被移除)普通读写 1 2 3 public int getInt (Object o, long offset) public void putInt (Object o, long offset, int x)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public class UnsafeTest { public static void main (String[] args) throws IllegalAccessException, NoSuchFieldException { UnsafeTest unsafeTest = new UnsafeTest (); Unsafe unsafe = unsafeTest.getUnsafe(); Guard guard = new Guard (); Field field = guard.getClass().getDeclaredField("value" ); unsafe.putInt(guard, unsafe.objectFieldOffset(field), 100 ); System.out.println("guard.getValue() = " + guard.getValue()); } public Unsafe getUnsafe () throws IllegalAccessException { Field unsafeField = Unsafe.class.getDeclaredFields()[0 ]; unsafeField.setAccessible(true ); return (Unsafe) unsafeField.get(null ); } } class Guard { private int value = 1 ; public int getValue () { return value; } }
内存屏障 主要为了避免代码重排序比如:使用loadFence()
,则屏障前的load操作不能被重排序到屏障后,屏障后的load操作不能被重排序到屏障前 1 2 3 4 5 public void loadFence () public void storeFence () public void fullFence ()
线程调度 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public void unpark (Object thread) public void park (boolean isAbsolute, long time) @Deprecated public native void monitorEnter (Object o) @Deprecated public native void monitorExit (Object o) @Deprecated public native boolean tryMonitorEnter (Object o)
park
方法,unpark
方法,看过LockSupport
类的都不会陌生,这两个方法主要用来挂起和唤醒线程LockSupport
中的park
和unpark
方法正是通过Unsafe来实现的:1 2 3 4 5 6 7 8 9 10 11 public static void unpark (Thread thread) { if (thread != null ) U.unpark(thread); } public static void park (Object blocker) { Thread t = Thread.currentThread(); setBlocker(t, blocker); U.park(false , 0L ); setBlocker(t, null ); }
monitorEnter
方法和monitorExit
方法用于加锁,Java中的synchronized
锁就是通过这两个指令来实现的final 原理 1 2 3 public class Main6 { final int a = 20 ; }
字节码如下:
1 2 3 4 5 6 7 0 aload_0 1 invokespecial #1 <java/lang/Object.<init> : ()V> 4 aload_0 5 bipush 20 # 将值直接放入栈中 7 putfield #2 # Field a:I # 此处有个写屏障 10 return
final变量的赋值通过putfield指令来完成,这条指令后会加入写屏障,避免其他线程读到他的值不会出现为零值的问题
其他线程访问final修饰的变量:
赋值一份放入栈中,直接访问 大于short的最大值,会将其复制到类的常量池,访问时从常量池取 不可变 1 2 3 4 public final class String implements java .io.Serializable, Comparable<String>, CharSequence { private final char value[]; }
无状态 状态信息:成员变量保存的数据
无状态:没有成员变量
如果一个类没有任何成员变量,那他就是线程安全的
ThreadLocal 基本介绍 基本使用 方法 描述 ThreadLocal<>() 创建ThreadLocal对象 protected T initialValue() 返回:当前线局部变量,的初始值 public void set( T value) 设置:当前线程绑定,的局部变量 public T get() 获取:当前线程绑定,的局部变量 public void remove() 移除:当前线程绑定,的局部变量
1 2 3 4 5 6 7 8 9 10 11 12 13 class MyDemo { private static ThreadLocal<String> t1 = new ThreadLocal <>(); private String content; public String getContent () { return t1.get(); } public void setContent (String content) { t1.set(content); } }
1 2 3 4 5 6 7 8 for (int i = 0 ; i < 5 ; i++) { String finalI = "" + i; new Thread (() -> { myDemo.setContent(finalI); String content = myDemo.getContent(); }).start(); }
实现原理 底层结构 JDK8以前:
JDK8以后:
成员变量 每个Thread线程持有一个ThreadLocalMap
对象 1 2 3 4 public class Thread implements Runnable { ThreadLocal.ThreadLocalMap inheritableThreadLocals = null ; }
1 2 3 4 5 6 7 8 public class ThreadLocal <T> { private final int threadLocalHashCode = nextHashCode(); private static AtomicInteger nextHashCode = new AtomicInteger (); private static final int HASH_INCREMENT = 0x61c88647 ; }
成员方法 返回线程局部变量的初始值(此方法缺省,为了让子类覆盖而设计的) 1 2 3 protected T initialValue () { return null ; }
计算哈希值(每次以斐波纳契数/黄金分割数递增),好处是分布均匀 1 2 3 private static int nextHashCode () { return nextHashCode.getAndAdd(HASH_INCREMENT); }
1 2 3 4 5 6 7 8 9 10 11 12 13 public void set (T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null ) { map.set(this , value); } else { createMap(t, value); } } ThreadLocalMap getMap (Thread t) { return t.threadLocals; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 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(); } private T setInitialValue () { T value = initialValue(); Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null ) { map.set(this , value); } else { createMap(t, value); } if (this instanceof TerminatingThreadLocal) { TerminatingThreadLocal.register((TerminatingThreadLocal<?>) this ); } return value; } protected T initialValue () { return null ; }
1 2 3 4 5 6 public void remove () { ThreadLocalMap m = getMap(Thread.currentThread()); if (m != null ) { m.remove(this ); } }
ThreadLocalMap 成员属性 是ThreadLocal内部类,用独立的方式实现了Map的功能,内部Entry也是独立实现
1 2 3 4 5 6 7 8 9 10 11 private static final int INITIAL_CAPACITY = 16 ;private Entry[] table;private int size = 0 ;private int threshold;
存储结构Entry:
继承WeakReference,key是弱引用,以便将ThreadLocal生命周期与线程生命周期解绑 1 2 3 4 5 6 7 8 static class Entry extends WeakReference <ThreadLocal<?>> { Object value; Entry(ThreadLocal<?> k, Object v) { super (k); value = v; } }
构造方法(是延迟初始化的,Thread第一次存储firstKey-firstValue时才会创建ThreadLocalMap
)
1 2 3 4 5 6 7 8 9 ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) { table = new Entry [INITIAL_CAPACITY]; int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1 ); table[i] = new Entry (firstKey, firstValue); size = 1 ; setThreshold(INITIAL_CAPACITY); }
成员方法 添加数据:
一直探测下一个地址,直到有空的地址后插入 若插入后Map数量超过阈值,数组扩容为原来两倍 探测过程中,key为null的脏Entry会被垃圾清理,并复用位置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 private void set (ThreadLocal<?> key, Object value) { Entry[] tab = table; int len = tab.length; int i = key.threadLocalHashCode & (len-1 ); for (Entry e = tab[i]; e != null ; e = tab[i = nextIndex(i, len)]) { ThreadLocal<?> k = e.get(); if (k == key) { e.value = value; return ; } if (k == null ) { replaceStaleEntry(key, value, i); return ; } } tab[i] = new Entry (key, value); int sz = ++size; if (!cleanSomeSlots(i, sz) && sz >= threshold) rehash(); }
1 2 3 4 5 6 7 8 9 private static int nextIndex (int i, int len) { return ((i + 1 < len) ? i + 1 : 0 ); } private static int prevIndex (int i, int len) { return ((i - 1 >= 0 ) ? i - 1 : len - 1 ); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 private void replaceStaleEntry (ThreadLocal<?> key, Object value, int staleSlot) { Entry[] tab = table; int len = tab.length; Entry e; int slotToExpunge = staleSlot; for (int i = prevIndex(staleSlot, len); (e = tab[i]) != null ; i = prevIndex(i, len)) if (e.get() == null ) slotToExpunge = i; for (int i = nextIndex(staleSlot, len); (e = tab[i]) != null ; i = nextIndex(i, len)) { ThreadLocal<?> k = e.get(); if (k == key) { e.value = value; tab[i] = tab[staleSlot]; tab[staleSlot] = e; if (slotToExpunge == staleSlot) slotToExpunge = i; cleanSomeSlots(expungeStaleEntry(slotToExpunge), len); return ; } if (k == null && slotToExpunge == staleSlot) slotToExpunge = i; } tab[staleSlot].value = null ; tab[staleSlot] = new Entry (key, value); if (slotToExpunge != staleSlot) cleanSomeSlots(expungeStaleEntry(slotToExpunge), len); }
获取数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 private Entry getEntry (ThreadLocal<?> key) { int i = key.threadLocalHashCode & (table.length - 1 ); Entry e = table[i]; if (e != null && e.get() == key) return e; else return getEntryAfterMiss(key, i, e); } private Entry getEntryAfterMiss (ThreadLocal<?> key, int i, Entry e) { Entry[] tab = table; int len = tab.length; while (e != null ) { ThreadLocal<?> k = e.get(); if (k == key) return e; if (k == null ) expungeStaleEntry(i); else i = nextIndex(i, len); e = tab[i]; } return null ; }
rehash:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 private void rehash () { expungeStaleEntries(); if (size >= threshold - threshold / 4 ) resize(); } private void expungeStaleEntries () { Entry[] tab = table; int len = tab.length; for (int j = 0 ; j < len; j++) { Entry e = tab[j]; if (e != null && e.get() == null ) expungeStaleEntry(j); } }
remove:
1 2 3 4 5 6 7 8 9 10 11 12 private void remove (ThreadLocal<?> key) { Entry[] tab = table; int len = tab.length; int i = key.threadLocalHashCode & (len-1 ); for (Entry e = tab[i]; e != null ; e = tab[i = nextIndex(i, len)]) { if (e.get() == key) { e.clear(); expungeStaleEntry(i); return ; } } }
探测式清理方法 1 private int expungeStaleEntry (int staleSlot) {}
启发式清理 向后循环扫描,发现过期数据就用探测式清理方法 ,来清理 加入当前数组长度为16,16->8->4->2->1,会向后扫描四次 假如扫到了垃圾,就又恢复到16,重新开始16->8->4… 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 private boolean cleanSomeSlots (int i, int n) { boolean removed = false ; Entry[] tab = table; int len = tab.length; do { i = nextIndex(i, len); Entry e = tab[i]; if (e != null && e.get() == null ) { n = len; removed = true ; i = expungeStaleEntry(i); } } while ( (n >>>= 1 ) != 0 ); return removed; }
InheritableThreadLocal 基本使用 父子线程:创建子线程的就是父线程,比如实例中的main线程就是父线程
想实现线程间局部变量传递,可以使用InheritableThreadLocal
1 2 3 4 5 6 7 8 9 public static void main (String[] args) { InheritableThreadLocal<String> threadLocal = new InheritableThreadLocal <>(); threadLocal.set("hello" ); new Thread (() -> { String s = threadLocal.get(); }).start(); }
实现原理 InheritableThreadLocal源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class InheritableThreadLocal <T> extends ThreadLocal <T> { protected T childValue (T parentValue) { return parentValue; } ThreadLocalMap getMap (Thread t) { return t.inheritableThreadLocals; } void createMap (Thread t, T firstValue) { t.inheritableThreadLocals = new ThreadLocalMap (this , firstValue); } }
在Thread的构造方法中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 private void init (ThreadGroup g, Runnable target, String name, long stackSize, AccessControlContext acc, boolean inheritThreadLocals) { Thread parent = currentThread(); if (inheritThreadLocals && parent.inheritableThreadLocals != null ) { this .inheritableThreadLocals = ThreadLocal.createInheritedMap(parent.inheritableThreadLocals); } } static ThreadLocalMap createInheritedMap (ThreadLocalMap parentMap) { return new ThreadLocalMap (parentMap); } private ThreadLocalMap (ThreadLocalMap parentMap) { Entry[] parentTable = parentMap.table; int len = parentTable.length; setThreshold(len); table = new Entry [len]; for (int j = 0 ; j < len; j++) { Entry e = parentTable[j]; if (e != null ) { @SuppressWarnings("unchecked") ThreadLocal<Object> key = (ThreadLocal<Object>) e.get(); if (key != null ) { Object value = key.childValue(e.value); Entry c = new Entry (key, value); int h = key.threadLocalHashCode & (len - 1 ); while (table[h] != null ) h = nextIndex(h, len); table[h] = c; size++; } } } }