在并发编程中,除了可以使用锁机制来保证线程安全,JDK 中还提供了 ThreadLocal 类来保证多个线程能够安全访问共享变量。本章简单介绍 ThreadLocal 的核心原理。
本文涉及的知识点如下。
—ThreadLocal 的基本概念。
—ThreadLocal 的使用案例。
—ThreadLocal 的核心原理。
—ThreadLocal 变量的继承性。
—InheritableThreadLocal 的使用案例。
—InheritableThreadLocal 的核心原理。
ThreadLocal 的基本概念
在并发编程中,多个线程同时访问同一个共享变量,可能会出现线程安全的问题。为了保证在多线程环境下访问共享变量的安全性,通常会在访问共享变量的时候加锁,以实现线程同步的效果。
使用同步锁机制保证多线程访问共享变量的安全性的原理如图 14-1 所示。该机制能够保证同一时刻只有一个线程访问共享变量,从而确保在多线程环境下访问共享变量的安全性。
另外,为了更加灵活地确保线程的安全性,JDK 中提供了一个 ThreadLocal 类,ThreadLocal 类能够支持本地变量。在使用 ThreadLocal 类访问共享变量时,会在每个线程的本地内存中都存储一份这个共享变量的副本。在多个线程同时对这个共享变量进行读写操作时,实际上操作的是本地内存中的变量副本,多个线程之间互不干扰,从而避免了线程安全的问题。使用 ThreadLocal 访问共享变量的示意图如图 14-2 所示。
ThreadLocal 的使用案例
本节主要实现两个通过 ThreadLocal 操作线程本地变量的案例,以此加深读者对 ThreadLocal 的理解。
案例一的主要实现逻辑:在案例程序中分别创建名称为 Thread-A 和 Thread-B 的两个线程, 在 Thread-A 线程和 Thread-B 线程的 run()方法中通过 ThreadLocal 保存本地变量,随后打印 Thread-A 线程和 Thread-B 线程中保存的本地变量。最后,启动 Thread-A 线程和 Thread-B 线程。
案例一的核心代码如下。
/**
*@author binghe
*@version 1.0.0
*@description ThreadLocal 案例程序
*/
public class ThreadLocalTest {
private static final ThreadLocal<String> THREAD_LOCAL = new
ThreadLocal<String>();
public static void main(String[]
args){ Thread threadA = new
Thread(()->{
THREAD_LOCAL.set("ThreadA: " + Thread.currentThread().getName());
System.out.println(Thread.currentThread().getName() + "本地变量中的值为: "
+ THREAD_LOCAL.get());
}, "Thread-A");
Thread threadB = new Thread(()->{
THREAD_LOCAL.set("ThreadB: " + Thread.currentThread().getName());
System.out.println(Thread.currentThread().getName() + "本地变量中的值为: "
+ THREAD_LOCAL.get());
}, "Thread-B");
threadA.start();
threadB.start();
}
}
运行上述代码,输出结果如下。
Thread-A 本地变量中的值为: ThreadA: Thread-A
Thread-B 本地变量中的值为: ThreadB: Thread-B
从输出结果可以看出,Thread-A 线程和 Thread-B 线程通过 ThreadLocal 保存了本地变量, 并未正确打印出结果。
案例二的主要实现逻辑:在案例一的基础上为 Thread-B 线程增加删除 ThreadLocal 中保存的本地变量的操作,随后打印结果来证明删除 Thread-B 线程中的本地变量不会影响 Thread-A 线程中的本地变量。
案例二的核心代码如下。
/**
*@author binghe
*@version 1.0.0
* @description ThreadLocal 案例程序
*/
public class ThreadLocalTest {
private static final ThreadLocal<String> THREAD_LOCAL = new
ThreadLocal<String>();
public static void main(String[]
args){ Thread threadA = new
Thread(()->{
THREAD_LOCAL.set("ThreadA: " + Thread.currentThread().getName());
System.out.println(Thread.currentThread().getName() + "本地变量中的值为: "
+ THREAD_LOCAL.get());
System.out.println(Thread.currentThread().getName() + "未删除本地变量,本地变量中的值为: " + THREA