# 基本使用
JDK的lang包下提供了ThreadLocal类,我们可以使用它创建一个线程变量,线程变量的作用域仅在于此线程内 。<br />用2个示例来展示一下ThreadLocal的用法 。
**示例一:**```javaThreadLocal<Integer> threadLocal = new ThreadLocal<>();
【ThreadLocal的使用及原理解析】System.out.println(threadLocal.get());threadLocal.set(1);System.out.println(threadLocal.get());threadLocal.remove();System.out.println(threadLocal.get());```输出:```powershellnull1null```
这个示例展示了ThreadLocal提供的所有方法,ThreadLocal中提供了三个方法,分别是:
- get:获取变量值- set:设置变量值- remove:删除变量值
**示例二:**```java// 创建一个MyRun类class MyRun implements Runnable {
// 创建2个线程变量,var1、var2 private ThreadLocal<Integer> var1 = new ThreadLocal<>(); private ThreadLocal<String> var2 = new ThreadLocal<>();
@Override public void run() { // 循环调用m方法5次 for (int i = 0; i < 5; i++) { m(); } }
public void m() { // 当前线程名称 String name = Thread.currentThread().getName();
// var1变量从1开始,m每次调用递增1 Integer v = var1.get(); if(v == null) { var1.set(1); }else { var1.set(v + 1); }
// var2变量 = 线程名 - var1值 var2.set(name + "-" + var1.get());
// 打印 print(); }
public void print() { String name = Thread.currentThread().getName(); System.out.println(name + ", var1: " + var1.get() + ", var2: " + var2.get()); }}```
创建2个线程,执行同一个MyRun:```javaMyRun myRun = new MyRun();Thread t1 = new Thread(myRun);Thread t2 = new Thread(myRun);t1.start();t2.start();```输出:```powershellThread-0, var1: 1, var2: Thread-0-1Thread-1, var1: 1, var2: Thread-1-1Thread-0, var1: 2, var2: Thread-0-2Thread-1, var1: 2, var2: Thread-1-2Thread-0, var1: 3, var2: Thread-0-3Thread-1, var1: 3, var2: Thread-1-3Thread-0, var1: 4, var2: Thread-0-4Thread-0, var1: 5, var2: Thread-0-5Thread-1, var1: 4, var2: Thread-1-4Thread-1, var1: 5, var2: Thread-1-5```
示例二展示了ThreadLocal的重要特点:<br />两个线程执行的是同一个MyRun对象,如果var1、var2是普通的成员变量,两个线程访问的将是同一个变量,这将会产生线程安全问题,然而从输出日志看来,t1、t2的var1、var2值其实是独立的,互不影响的 。
这是因为var1、var2是ThreadLocal类型,即是线程变量,它是绑定在线程上的,哪个线程来访问这段代码,就从哪个线程上获取var1、var2变量值,线程与线程之间是相互隔离的,因此也不存在线程安全问题 。
# 原理解析
ThreadLocal是如何实现这个效果的呢?<br />我们可以从ThreadLocal的源代码中一探究竟 。
其中,最关键是get方法,我将get相关的源代码都提取出来如下:```javapublic T get() { // 获取当前线程对象 Thread t = Thread.currentThread(); // 从当前线程中获取ThreadLocalMap对象 ThreadLocalMap map = getMap(t); if (map != null) { // 从ThreadLocalMap对象中获取当前ThreadLocal对应Entry ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { // 若Entry不为null,返回值 @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } // 如果获取ThreadLocalMap对象为null则返回默认值 return setInitialValue();}
经验总结扩展阅读
- 2023年9月14日迁居行吗 2023年9月14日是迁居的黄道吉日吗
- 家里干净怎么会有跳蚤
- 2023年10月5日是搬家的吉日吗 是吉祥的日子吗
- 油的沸点是多少度?
- 煮熟的虾怎么保存 冷藏还是冷冻
- 2023年10月12日搬家怎么样 是吉祥的日子吗
- 鞋子磨脚怎么办小妙招
- 2023年9月14日祭祖吉日一览表 2023年9月14日是祭祖的黄道吉日吗
- 酒驾20到80之间处罚一样吗
- 米字旗是哪国的国旗