3535public class ThreadLocalTest {
3636 private List<String > messages = Lists . newArrayList();
3737
38- public static final ` ThreadLocal ` < ThreadLocalTest > holder = ` ThreadLocal` .withInitial (ThreadLocalTest ::new );
38+ public static final ThreadLocal<ThreadLocalTest > holder = ThreadLocal . withInitial(ThreadLocalTest :: new );
3939
4040 public static void add(String message) {
4141 holder. get(). messages. add(message);
@@ -70,20 +70,19 @@ size: 0
7070
7171! [](. / images/ thread- local/ 2. png)
7272
73- 74- ` Thread ` 类有一个类型为`` ThreadLocal`.`ThreadLocalMap `` 的实例变量` threadLocals ` ,也就是说每个线程有一个自己的` ThreadLocalMap ` 。
73+ `Thread `类有一个类型为`ThreadLocal . ThreadLocalMap `的实例变量`threadLocals`,也就是说每个线程有一个自己的`ThreadLocalMap `。
7574
7675`ThreadLocalMap `有自己的独立实现,可以简单地将它的`key`视作`ThreadLocal `,`value`为代码中放入的值(实际上`key`并不是`ThreadLocal `本身,而是它的一个** 弱引用** )。
7776
7877每个线程在往`ThreadLocal `里放值的时候,都会往自己的`ThreadLocalMap `里存,读也是以`ThreadLocal `作为引用,在自己的`map`里找对应的`key`,从而实现了** 线程隔离** 。
7978
8079`ThreadLocalMap `有点类似`HashMap `的结构,只是`HashMap `是由** 数组+ 链表** 实现的,而`ThreadLocalMap `中并没有** 链表** 结构。
8180
82- 我们还要注意` Entry ` , 它的` key ` 是`` ThreadLocal` <?> k ` ,继承自`WeakReference, 也就是我们常说的弱引用类型。
81+ 我们还要注意`Entry `, 它的`key`是`ThreadLocal<?> k` ,继承自`WeakReference ` , 也就是我们常说的弱引用类型。
8382
8483### GC 之后key是否为null ?
8584
86- 回应开头的那个问题, ` ThreadLocal ` 的` key ` 是弱引用,那么在` ` ThreadLocal` .get() ` 的时候,发生` GC ` 之后,` key ` 是否是` null ` ?
85+ 回应开头的那个问题, `ThreadLocal ` 的`key`是弱引用,那么在`ThreadLocal . get()`的时候,发生`GC `之后,`key`是否是`null `?
8786
8887为了搞清楚这个问题,我们需要搞清楚`Java `的** 四种引用类型** :
8988
@@ -110,19 +109,19 @@ public class ThreadLocalDemo {
110109
111110 private static void test (String s ,boolean isGC ) {
112111 try {
113- new ` ThreadLocal ` <>(). set(s);
112+ new ThreadLocal<> (). set(s);
114113 if (isGC) {
115114 System . gc();
116115 }
117116 Thread t = Thread . currentThread();
118117 Class<? extends Thread > clz = t. getClass();
119118 Field field = clz. getDeclaredField(" threadLocals" );
120119 field. setAccessible(true );
121- Object ` ThreadLocalMap ` = field. get(t);
122- Class<?> tlmClass = ` ThreadLocalMap ` . getClass();
120+ Object ThreadLocalMap = field. get(t);
121+ Class<?> tlmClass = ThreadLocalMap . getClass();
123122 Field tableField = tlmClass. getDeclaredField(" table" );
124123 tableField. setAccessible(true );
125- Object [] arr = (Object []) tableField. get(` ThreadLocalMap ` );
124+ Object [] arr = (Object []) tableField. get(ThreadLocalMap );
126125 for (Object o : arr) {
127126 if (o != null ) {
128127 Class<?> entryClass = o. getClass();
@@ -142,8 +141,8 @@ public class ThreadLocalDemo {
142141
143142结果如下:
144143```java
145- 弱引用key: java. lang. ` ThreadLocal ` @433619b6 ,值: abc
146- 弱引用key: java. lang. ` ThreadLocal ` @418a15e3 ,值: java.lang.ref. SoftReference @bf97a12
144+ 弱引用key: java.lang. ThreadLocal @433619b6 ,值: abc
145+ 弱引用key: java.lang. ThreadLocal @418a15e3 ,值: java.lang.ref. SoftReference @bf97a12
147146-- gc后--
148147弱引用key: null ,值: def
149148```
@@ -162,7 +161,7 @@ new ThreadLocal<>().set(s);
162161
163162这个问题刚开始看,如果没有过多思考,** 弱引用** ,还有** 垃圾回收** ,那么肯定会觉得是`null `。
164163
165- 其实是不对的,因为题目说的是在做 `` ThreadLocal` .get() ` 操作,证明其实还是有** 强引用** 存在的,所以 ` key ` 并不为 ` null ` ,如下图所示,` ThreadLocal ` 的** 强引用** 仍然是存在的。
164+ 其实是不对的,因为题目说的是在做 `ThreadLocal . get()` 操作,证明其实还是有** 强引用** 存在的,所以 `key` 并不为 `null `,如下图所示,`ThreadLocal `的** 强引用** 仍然是存在的。
166165
167166! [image. png](. / images/ thread- local/ 5. png)
168167
@@ -217,8 +216,8 @@ public class ThreadLocal<T> {
217216 return nextHashCode. getAndAdd(HASH_INCREMENT );
218217 }
219218
220- static class ` ThreadLocalMap ` {
221- ` ThreadLocalMap `(` ThreadLocal ` < ? > firstKey, Object firstValue) {
219+ static class ThreadLocalMap {
220+ ThreadLocalMap ( ThreadLocal<?> firstKey , Object firstValue ) {
222221 table = new Entry [INITIAL_CAPACITY ];
223222 int i = firstKey. threadLocalHashCode & (INITIAL_CAPACITY - 1 );
224223
@@ -230,7 +229,7 @@ public class ThreadLocal<T> {
230229}
231230```
232231
233- 每当创建一个` ThreadLocal ` 对象,这个`` ThreadLocal` .nextHashCode ` 这个值就会增长 ` 0x61c88647 ` 。
232+ 每当创建一个`ThreadLocal `对象,这个`ThreadLocal . nextHashCode` 这个值就会增长 `0x61c88647 ` 。
234233
235234这个值很特殊,它是** 斐波那契数** 也叫 ** 黄金分割数** 。`hash`增量为 这个数字,带来的好处就是 `hash` ** 分布非常均匀** 。
236235
@@ -244,7 +243,7 @@ public class ThreadLocal<T> {
244243
245244> ** 注明:** 下面所有示例图中,** 绿色块** `Entry `代表** 正常数据** ,** 灰色块** 代表`Entry `的`key`值为`null `,** 已被垃圾回收** 。** 白色块** 表示`Entry `为`null `。
246245
247- 虽然` ThreadLocalMap ` 中使用了** 黄金分隔数来 ** 作为` hash ` 计算因子,大大减少了` Hash ` 冲突的概率,但是仍然会存在冲突。
246+ 虽然`ThreadLocalMap `中使用了** 黄金分割数来 ** 作为`hash`计算因子,大大减少了`Hash `冲突的概率,但是仍然会存在冲突。
248247
249248`HashMap `中解决冲突的方法是在数组上构造一个** 链表** 结构,冲突的数据挂载到链表上,如果链表长度超过一定数量则会转化成** 红黑树** 。
250249
@@ -403,7 +402,7 @@ private static int prevIndex(int i, int len) {
403402`java.lang. ThreadLocal . ThreadLocalMap . replaceStaleEntry()`:
404403
405404```java
406- private void replaceStaleEntry(` ThreadLocal ` < ? > key, Object value,
405+ private void replaceStaleEntry(ThreadLocal<?> key, Object value,
407406 int staleSlot) {
408407 Entry [] tab = table;
409408 int len = tab. length;
@@ -687,7 +686,7 @@ private void resize() {
687686
688687! [](. / images/ thread- local/ 27. png)
689688
690- 我们以` get(ThreadLocal1) ` 为例,通过` hash ` 计算后,正确的` slot ` 位置应该是4,而` index=4 ` 的槽位已经有了数据,且` key ` 值不等于``ThreadLocal ` 1 ` ,所以需要继续往后迭代查找。
689+ 我们以`get(ThreadLocal1 )`为例,通过`hash`计算后,正确的`slot`位置应该是4 ,而`index= 4 `的槽位已经有了数据,且`key`值不等于`ThreadLocal1 `,所以需要继续往后迭代查找。
691690
692691迭代到`index= 5 `的数据时,此时`Entry . key= null `,触发一次探测式数据回收操作,执行`expungeStaleEntry()`方法,执行完后,`index 5 ,8 `的数据都会被回收,而`index 6 ,7 `的数据都会前移,此时继续往后迭代,到`index = 6 `的时候即找到了`key`值相等的`Entry `数据,如下图所示:
693692
@@ -698,7 +697,7 @@ private void resize() {
698697`java.lang. ThreadLocal . ThreadLocalMap . getEntry()`:
699698
700699```java
701- private Entry getEntry(` ThreadLocal ` < ? > key) {
700+ private Entry getEntry(ThreadLocal<?> key) {
702701 int i = key. threadLocalHashCode & (table. length - 1 );
703702 Entry e = table[i];
704703 if (e != null && e. get() == key)
@@ -707,7 +706,7 @@ private Entry getEntry(`ThreadLocal`<?> key) {
707706 return getEntryAfterMiss(key, i, e);
708707}
709708
710- private Entry getEntryAfterMiss(` ThreadLocal ` < ? > key, int i, Entry e) {
709+ private Entry getEntryAfterMiss(ThreadLocal<?> key, int i, Entry e) {
711710 Entry [] tab = table;
712711 int len = tab. length;
713712
0 commit comments