@@ -18,90 +18,33 @@ head:
1818
1919### ThreadLocal 有什么用?
2020
21- 通常情况下,我们创建的变量是可以被任何一个线程访问并修改的。 ** 如果想实现每一个线程都有自己的专属本地变量该如何解决呢 ?**
21+ 通常情况下,我们创建的变量可以被任何一个线程访问和修改。这在多线程环境中可能导致数据竞争和线程安全问题。那么, ** 如果想让每个线程都有自己的专属本地变量,该如何实现呢 ?**
2222
23- JDK 中自带的 ` ThreadLocal ` 类正是为了解决这样的问题。 ** ` ThreadLocal ` 类主要解决的就是让每个线程绑定自己的值,可以将 ` ThreadLocal ` 类形象的比喻成存放数据的盒子,盒子中可以存储每个线程的私有数据。 **
23+ JDK 中提供的 ` ThreadLocal ` 类正是为了解决这个问题。 ** ` ThreadLocal ` 类允许每个线程绑定自己的值 ** ,可以将其形象地比喻为一个“存放数据的盒子”。每个线程都有自己独立的盒子,用于存储私有数据,确保不同线程之间的数据互不干扰。
2424
25- 如果你创建了一个 ` ThreadLocal ` 变量,那么访问这个变量的每个线程都会有这个变量的本地副本, 这也是` ThreadLocal ` 变量名的由来。他们可以使用 ` get() ` 和 ` set() ` 方法来获取默认值或将其值更改为当前线程所存的副本的值 ,从而避免了线程安全问题。
25+ 当你创建一个 ` ThreadLocal ` 变量时,每个访问该变量的线程都会拥有一个独立的副本。 这也是 ` ThreadLocal ` 名称的由来。线程可以通过 ` get() ` 方法获取自己线程的本地副本,或通过 ` set() ` 方法修改该副本的值 ,从而避免了线程安全问题。
2626
27- 再举个简单的例子:两个人去宝屋收集宝物,这两个共用一个袋子的话肯定会产生争执,但是给他们两个人每个人分配一个袋子的话就不会出现这样的问题。如果把这两个人比作线程的话,那么 ThreadLocal 就是用来避免这两个线程竞争的。
28-
29- ### 如何使用 ThreadLocal?
30-
31- 相信看了上面的解释,大家已经搞懂 ` ThreadLocal ` 类是个什么东西了。下面简单演示一下如何在项目中实际使用 ` ThreadLocal ` 。
27+ 举个简单的例子:假设有两个人去宝屋收集宝物。如果他们共用一个袋子,必然会产生争执;但如果每个人都有一个独立的袋子,就不会有这个问题。如果将这两个人比作线程,那么 ` ThreadLocal ` 就是用来避免这两个线程竞争同一个资源的方法。
3228
3329``` java
34- import java.text.SimpleDateFormat ;
35- import java.util.Random ;
36-
37- public class ThreadLocalExample implements Runnable {
38-
39- // SimpleDateFormat 不是线程安全的,所以每个线程都要有自己独立的副本
40- private static final ThreadLocal<SimpleDateFormat > formatter = ThreadLocal . withInitial(() - > new SimpleDateFormat (" yyyyMMdd HHmm" ));
41-
42- public static void main (String [] args ) throws InterruptedException {
43- ThreadLocalExample obj = new ThreadLocalExample ();
44- for (int i= 0 ; i< 10 ; i++ ){
45- Thread t = new Thread (obj, " " + i);
46- Thread . sleep(new Random (). nextInt(1000 ));
47- t. start();
48- }
49- }
50-
51- @Override
52- public void run () {
53- System . out. println(" Thread Name= " + Thread . currentThread(). getName()+ " default Formatter = " + formatter. get(). toPattern());
54- try {
55- Thread . sleep(new Random (). nextInt(1000 ));
56- } catch (InterruptedException e) {
57- e. printStackTrace();
58- }
59- // formatter pattern is changed here by thread, but it won't reflect to other threads
60- formatter. set(new SimpleDateFormat ());
30+ public class ThreadLocalExample {
31+ private static ThreadLocal<Integer > threadLocal = ThreadLocal . withInitial(() - > 0 );
6132
62- System . out. println(" Thread Name= " + Thread . currentThread(). getName()+ " formatter = " + formatter. get(). toPattern());
33+ public static void main (String [] args ) {
34+ Runnable task = () - > {
35+ int value = threadLocal. get();
36+ value += 1 ;
37+ threadLocal. set(value);
38+ System . out. println(Thread . currentThread(). getName() + " Value: " + threadLocal. get());
39+ };
40+
41+ Thread thread1 = new Thread (task, " Thread-1" );
42+ Thread thread2 = new Thread (task, " Thread-2" );
43+
44+ thread1. start(); // 输出: Thread-1 Value: 1
45+ thread2. start(); // 输出: Thread-2 Value: 1
6346 }
64-
6547}
66-
67- ```
68-
69- 输出结果 :
70-
71- ``` plain
72- Thread Name= 0 default Formatter = yyyyMMdd HHmm
73- Thread Name= 0 formatter = yy-M-d ah:mm
74- Thread Name= 1 default Formatter = yyyyMMdd HHmm
75- Thread Name= 2 default Formatter = yyyyMMdd HHmm
76- Thread Name= 1 formatter = yy-M-d ah:mm
77- Thread Name= 3 default Formatter = yyyyMMdd HHmm
78- Thread Name= 2 formatter = yy-M-d ah:mm
79- Thread Name= 4 default Formatter = yyyyMMdd HHmm
80- Thread Name= 3 formatter = yy-M-d ah:mm
81- Thread Name= 4 formatter = yy-M-d ah:mm
82- Thread Name= 5 default Formatter = yyyyMMdd HHmm
83- Thread Name= 5 formatter = yy-M-d ah:mm
84- Thread Name= 6 default Formatter = yyyyMMdd HHmm
85- Thread Name= 6 formatter = yy-M-d ah:mm
86- Thread Name= 7 default Formatter = yyyyMMdd HHmm
87- Thread Name= 7 formatter = yy-M-d ah:mm
88- Thread Name= 8 default Formatter = yyyyMMdd HHmm
89- Thread Name= 9 default Formatter = yyyyMMdd HHmm
90- Thread Name= 8 formatter = yy-M-d ah:mm
91- Thread Name= 9 formatter = yy-M-d ah:mm
92- ```
93-
94- 从输出中可以看出,虽然 ` Thread-0 ` 已经改变了 ` formatter ` 的值,但 ` Thread-1 ` 默认格式化值与初始化值相同,其他线程也一样。
95-
96- 上面用于创建 ` ThreadLocal ` 变量的那段代码用到了 Java8 的知识,它等于下面这段代码,如果你写了下面这段代码的话,IDEA 会提示你转换为 Java8 的格式(IDEA 真的不错!)。因为 ThreadLocal 类在 Java 8 中扩展,使用一个新的方法` withInitial() ` ,将 Supplier 功能接口作为参数。
97-
98- ``` java
99- private static final ThreadLocal<SimpleDateFormat > formatter = new ThreadLocal<SimpleDateFormat > (){
100- @Override
101- protected SimpleDateFormat initialValue (){
102- return new SimpleDateFormat (" yyyyMMdd HHmm" );
103- }
104- };
10548```
10649
10750### ⭐️ThreadLocal 原理了解吗?
0 commit comments