《Java 多執行緒程式設計核心技術》筆記——第3章 執行緒間通訊(四)
文章目錄
宣告:
本部落格是本人在學習《Java 多執行緒程式設計核心技術》後整理的筆記,旨在方便複習和回顧,並非用作商業用途。
本部落格已標明出處,如有侵權請告知,馬上刪除。
3.3 類 ThreadLocal 的使用
變數值的共享可以使用 public static 變數的形式,所有的執行緒都使用同一個 public static 變數。如果想實現每一個執行緒都有自己的共享變數該如何解決呢?
JDK 中提供的類 ThreadLocal 正是為了解決這樣的問題。
類 ThreadLocal 主要解決的就是每個執行緒繫結自己的值,可以將 ThreadLocal 類比喻成全域性存放資料的盒子,盒子中可以儲存每個執行緒的私有資料。
3.3.1 方法 get() 與 null
建立測試類如下:
public class Run {
public static ThreadLocal tl = new ThreadLocal();
public static void main(String[] args) {
if (tl.get() == null) {
System.out.println("從未放過值");
tl.set("我的值");
}
System.out.println(tl.get());
System.out.println(tl.get());
}
}
執行結果:
從未放過值
我的值
我的值
從執行結果來看第一次呼叫 tl 物件的 get() 方法時返回的值是 null,通過呼叫 set() 方法賦值後順利取出值並列印到控制檯上。類 Threadlocal 解決的是變數在不同執行緒間的隔離性,也就是不同執行緒擁有自己的值,不同執行緒中的值是可以放入 Threadlocal 類中進行儲存的。
3.3.2 驗證執行緒變數的隔離性
-
建立公共類
public class Tools { public static ThreadLocal tl = new ThreadLocal(); }
-
建立兩個自定義執行緒類
public class ThreadA extends Thread { @Override public void run() { try { for (int i = 0; i < 100; i++) { if (Tools.tl.get() == null) { Tools.tl.set("ThreadA" + (i + 1)); } else { System.out.println("ThreadA get Value=" + Tools.tl.get()); } Thread.sleep(200); } } catch (InterruptedException e) { e.printStackTrace(); } } }
public class ThreadB extends Thread { @Override public void run() { try { for (int i = 0; i < 100; i++) { if (Tools.tl.get() == null) { Tools.tl.set("ThreadB" + (i + 1)); } else { System.out.println("ThreadB get Value=" + Tools.tl.get()); } Thread.sleep(200); } } catch (InterruptedException e) { e.printStackTrace(); } } }
-
建立測試類
public class Run { public static void main(String[] args) { try { ThreadA a = new ThreadA(); ThreadB b = new ThreadB(); a.start(); b.start(); for (int i = 0; i < 100; i++) { if (Tools.tl.get() == null) { Tools.tl.set("Main" + (i + 1)); } else { System.out.println("Main get Value=" + Tools.tl.get()); } Thread.sleep(200); } } catch (InterruptedException e) { e.printStackTrace(); } } }
執行結果:
ThreadB get Value=ThreadB1 ThreadA get Value=ThreadA1 Main get Value=Main1 ThreadB get Value=ThreadB1 Main get Value=Main1 ThreadA get Value=ThreadA1 ThreadB get Value=ThreadB1 ThreadA get Value=ThreadA1 Main get Value=Main1 ThreadB get Value=ThreadB1 Main get Value=Main1 ...
分析:雖然 3 個執行緒都向 tl 物件中 set() 資料值,但每個執行緒還是能取出自己的資料。
在第一次呼叫 Threadlocal 類的 get() 方法返回值是 null,怎麼樣實現第一次呼叫 get() 不返回 null 呢?也就是具有預設值的效果。
3.3.3 解決 get() 返回 null 問題
-
繼承 ThreadLocal 類產生 ThreadLocalExt.java 類
public class ThreadLocalExt extends ThreadLocal { @Override protected Object initialValue() { return "我是預設值 第一次get不再為null"; } }
-
測試類
public class Run { public static ThreadLocalExt tl = new ThreadLocalExt(); public static void main(String[] args) { if (tl.get() == null) { System.out.println("從未放過值"); tl.set("我的值"); } System.out.println(tl.get()); System.out.println(tl.get()); } }
執行結果:
我是預設值 第一次get不再為null 我是預設值 第一次get不再為null
此案例僅僅證明 main 執行緒有自己的值,那其他執行緒是否會有自己的初始值呢?
3.3.4 再次驗證執行緒變數的隔離性
-
繼承 ThreadLocal 類產生 ThreadLocalExt.java 類
public class ThreadLocalExt extends ThreadLocal { @Override protected Object initialValue() { return new Date().getTime(); } }
-
建立工具類
public class Tools { public static ThreadLocalExt tl = new ThreadLocalExt(); }
-
建立自定義執行緒類
public class ThreadA extends Thread { @Override public void run() { try { for (int i = 0; i < 10; i++) { System.out.println("在ThreadA執行緒中取值=" + Tools.tl.get()); Thread.sleep(100); } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
-
測試類
public class Run { public static void main(String[] args) { try { for (int i = 0; i < 10; i++) { System.out.println(" 在Main執行緒中取值=" + Tools.tl.get()); Thread.sleep(100); } Thread.sleep(5000); ThreadA a = new ThreadA(); a.start(); } catch (InterruptedException e) { e.printStackTrace(); } } }
執行結果:
在Main執行緒中取值=1607801033539 在Main執行緒中取值=1607801033539 在Main執行緒中取值=1607801033539 在Main執行緒中取值=1607801033539 在Main執行緒中取值=1607801033539 在Main執行緒中取值=1607801033539 在Main執行緒中取值=1607801033539 在Main執行緒中取值=1607801033539 在Main執行緒中取值=1607801033539 在Main執行緒中取值=1607801033539 在ThreadA執行緒中取值=1607801039548 在ThreadA執行緒中取值=1607801039548 在ThreadA執行緒中取值=1607801039548 在ThreadA執行緒中取值=1607801039548 在ThreadA執行緒中取值=1607801039548 在ThreadA執行緒中取值=1607801039548 在ThreadA執行緒中取值=1607801039548 在ThreadA執行緒中取值=1607801039548 在ThreadA執行緒中取值=1607801039548 在ThreadA執行緒中取值=1607801039548
子執行緒和父執行緒各有各自所擁有的值。
3.4 類 InheritableThreadLocal 的使用
使用類 InheritableThreadLocal 可以在子執行緒中取得父執行緒繼承下來的值。
3.4.1 值繼承
使用 InheritableThreadLocal 類可以讓子執行緒從父執行緒中取得值。
示例如下:
-
繼承 InheritableThreadLocal 類產生 InheritableThreadLocalExt.java 類
public class InheritableThreadLocalExt extends InheritableThreadLocal { @Override protected Object initialValue() { return new Date().getTime(); } }
-
建立工具類
public class Tools { public static InheritableThreadLocalExt tl = new InheritableThreadLocalExt(); }
-
建立自定義執行緒類
public class ThreadA extends Thread { @Override public void run() { try { for (int i = 0; i < 10; i++) { System.out.println("在ThreadA執行緒中取值=" + Tools.tl.get()); Thread.sleep(100); } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
-
測試類
public class Run { public static void main(String[] args) { try { for (int i = 0; i < 10; i++) { System.out.println(" 在Main執行緒中取值=" + Tools.tl.get()); Thread.sleep(100); } Thread.sleep(5000); ThreadA a = new ThreadA(); a.start(); } catch (InterruptedException e) { e.printStackTrace(); } } }
執行結果:
在Main執行緒中取值=1607802334937 在Main執行緒中取值=1607802334937 在Main執行緒中取值=1607802334937 在Main執行緒中取值=1607802334937 在Main執行緒中取值=1607802334937 在Main執行緒中取值=1607802334937 在Main執行緒中取值=1607802334937 在Main執行緒中取值=1607802334937 在Main執行緒中取值=1607802334937 在Main執行緒中取值=1607802334937 在ThreadA執行緒中取值=1607802334937 在ThreadA執行緒中取值=1607802334937 在ThreadA執行緒中取值=1607802334937 在ThreadA執行緒中取值=1607802334937 在ThreadA執行緒中取值=1607802334937 在ThreadA執行緒中取值=1607802334937 在ThreadA執行緒中取值=1607802334937 在ThreadA執行緒中取值=1607802334937 在ThreadA執行緒中取值=1607802334937 在ThreadA執行緒中取值=1607802334937
分析:值成功地從父執行緒繼承下來
3.4.2 值繼承再修改
如果在繼承的同時還可以對值進行進一步的處理那就更好了。
-
修改類 InheritableThreadLocalExt.java 類
public class InheritableThreadLocalExt extends InheritableThreadLocal { @Override protected Object initialValue() { return new Date().getTime(); } @Override protected Object childValue(Object parentValue) { return parentValue + " 我在子執行緒加的~!"; } }
-
再次執行,結果如下
在Main執行緒中取值=1607802735419 在Main執行緒中取值=1607802735419 在Main執行緒中取值=1607802735419 在Main執行緒中取值=1607802735419 在Main執行緒中取值=1607802735419 在Main執行緒中取值=1607802735419 在Main執行緒中取值=1607802735419 在Main執行緒中取值=1607802735419 在Main執行緒中取值=1607802735419 在Main執行緒中取值=1607802735419 在ThreadA執行緒中取值=1607802735419 我在子執行緒加的~! 在ThreadA執行緒中取值=1607802735419 我在子執行緒加的~! 在ThreadA執行緒中取值=1607802735419 我在子執行緒加的~! 在ThreadA執行緒中取值=1607802735419 我在子執行緒加的~! 在ThreadA執行緒中取值=1607802735419 我在子執行緒加的~! 在ThreadA執行緒中取值=1607802735419 我在子執行緒加的~! 在ThreadA執行緒中取值=1607802735419 我在子執行緒加的~! 在ThreadA執行緒中取值=1607802735419 我在子執行緒加的~! 在ThreadA執行緒中取值=1607802735419 我在子執行緒加的~! 在ThreadA執行緒中取值=1607802735419 我在子執行緒加的~!
但在使用 InheritableThreadLocal 類需要注意一點的是,如果子執行緒在取得值的同時,主執行緒將 InheritableThreadLocal 中的值進行更改,那麼子執行緒取到的值還是舊值。
相關文章
- 《Java 多執行緒程式設計核心技術》筆記——第3章 執行緒間通訊(三)Java執行緒程式設計筆記
- java核心技術筆記--執行緒Java筆記執行緒
- java多執行緒5:執行緒間的通訊Java執行緒
- Java多執行緒-執行緒通訊Java執行緒
- java多執行緒間的通訊Java執行緒
- Java多執行緒學習——執行緒通訊Java執行緒
- Java併發程式設計之執行緒安全、執行緒通訊Java程式設計執行緒
- 多執行緒之間通訊及執行緒池執行緒
- Java多執行緒程式設計筆記9:ReentrantReadWriteLockJava執行緒程式設計筆記
- Java核心技術學習筆記——進階——第五章 Java多執行緒和併發程式設計——5.2 Java多執行緒實現Java筆記執行緒程式設計
- 多執行緒核心技術(1)-執行緒的基本方法執行緒
- Java多執行緒學習(3)執行緒同步與執行緒通訊Java執行緒
- 【Java】【多執行緒】兩個執行緒間的通訊、wait、notify、notifyAllJava執行緒AI
- Java多執行緒筆記Java執行緒筆記
- Android小知識-Java多執行緒相關(執行緒間通訊)上篇AndroidJava執行緒
- java多執行緒:執行緒間通訊——生產者消費者模型Java執行緒模型
- Swift多執行緒:使用Thread進行多執行緒間通訊,協調子執行緒任務Swift執行緒thread
- Java 多執行緒基礎(四)執行緒安全Java執行緒
- Java多執行緒程式設計筆記2:synchronized同步方法Java執行緒程式設計筆記synchronized
- Java多執行緒程式設計筆記10:單例模式Java執行緒程式設計筆記單例模式
- 手撕Java多執行緒(四)執行緒之間的協作Java執行緒
- 程式間通訊(linux程式與執行緒學習筆記)Linux執行緒筆記
- Java多執行緒學習(五)執行緒間通訊知識點補充Java執行緒
- 多執行緒之間的通訊執行緒
- [短文速讀 -5] 多執行緒程式設計引子:程式、執行緒、執行緒安全執行緒程式設計
- 說說Java執行緒間通訊Java執行緒
- 多執行緒筆記執行緒筆記
- Java執行緒通訊Java執行緒
- 多執行緒程式設計的核心思想執行緒程式設計
- Java多執行緒-執行緒中止Java執行緒
- Java多執行緒(四):volatileJava執行緒
- Android執行緒間通訊Android執行緒
- Java 多執行緒學習筆記Java執行緒筆記
- 多執行緒------執行緒與程式/執行緒排程/建立執行緒執行緒
- java多執行緒程式設計:你真的瞭解執行緒中斷嗎?Java執行緒程式設計
- 多執行緒程式設計基礎(一)-- 執行緒的使用執行緒程式設計
- 多執行緒Demo學習(執行緒的同步,簡單的執行緒通訊)執行緒
- python 多執行緒程式設計Python執行緒程式設計