# 基本使用
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之間處罰一樣嗎
- 米字旗是哪國的國旗
