Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 6ee3db6

Browse files
author
hailong.sha
committed
Update 万字详解ThreadLocal关键字.md
formation update
1 parent 6f73cee commit 6ee3db6

File tree

1 file changed

+19
-20
lines changed

1 file changed

+19
-20
lines changed

‎docs/java/multi-thread/万字详解ThreadLocal关键字.md‎

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
public 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

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /