ThreadLocal(上)介绍及使用篇

出现背景:

多线程访问同一个共享变量特别容易出现并发问题,特别是在多个线程需要对一个共享变量进行写入时,为了保证线程安全,一般使用者在访问共享变量时进行适当的同步。如图所示

image-20200323150913

同步的措施一般是加锁,这就需要使用者对锁有一定的了解,这就显然加重了使用者的负担,那么有没有一种方式可以做到,当创建一个变量后,每个线程对其进行访问的时候访问的是自己线程的变量呢?ThreadLocal他可以,虽然他不是为了解决这个问题出现的。

ThreadLocal介绍:

ThreadLocal是JDK包所提供的,它提供了线程本地变量,也就是说你创建了一个ThreadLocal变量,那么访问这个变量的每个线程都会有这个变量的一个本地副本,当多个线程进行同时操作时,实际上也是访问的是自己本地内存里面的变量,从而避免了线程安全问题,创建一个ThreadLocal变量后,每个调用线程都会复制一个备份到自己的本地内存,如图所示。
image_20200324155853

ThreadLocal使用案例:

本案例开启两个线程,在每个线程内部设置了本地线程变量,然后调用print函数打印当前本地变量值,打印后调用remove方法删除本地内存变量,代码如下:

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
public class ThreadLocalExample1 {

// (1) 创建ThreadLocal变量
static ThreadLocal<String> localVariable = new ThreadLocal<>();

// (2)print函数
static void print(String str){
// 打印当前线程本地内存中localVariable变量的值
System.out.println(str + ":" + localVariable.get());
// 2.1 清楚当前线程本地内存变量
// localVariable.remove();
}

public static void main(String[] args) {

// (3) 创建线程one
Thread threadOne = new Thread(new Runnable() {
@Override
public void run() {
// 设置threadOne中的本地变量localVariable的值
localVariable.set("threadOne local variable");
// 调用打印函数
print("threadOne");
System.out.println("threadOne remove after" + localVariable.get());
}
});


// 创建线程two
Thread threadTwo = new Thread(new Runnable() {
@Override
public void run() {
// 设置threadTwo线程中的本地线程变量
localVariable.set("threadTwo local variable");
// 调用打印函数
print("threadTwo");
// 打印本地线程变量
System.out.println("threadTwo remove after" + ":" + localVariable.get());
}
});

// (5)启动线程
threadOne.start();
threadTwo.start();
}
}

运行结果如下:

image_20200324162302

代码(1) 创建了一个ThreadLocal变量。

代码(3)和(4)创建了两个线程

代码(5) 启动两个线程

线程one中通过set方法设置了localvariable的值,这其实设置的就是线程one本地内存中的一个副本,这个副本线程Two是访问不了的,然后调用了print函数,通过get方法获取到了当前线程one本地内存中的localVariable的值。

线程Two的执行与one相似。

打开2.1的注释后,再次运行,看下执行结果:

image_20200324162106

ThreadLocal的基本使用就到这里了,下节说实现原理

喜欢关注公众号:

qrcode

评论

You forgot to set the shortname for Disqus. Please set it in _config.yml.