深入解析J.U.C并发包(十五)—— Thread - Specific Storage(ThreadLocal)模式
一、定義
Thread - Specific Storage就是“線程獨有的存儲庫”,該模式會對每個線程提供獨有的內存空間。
java.lang.ThreadLocal類提供了該模式的實現,ThreadLocal的實例是一種集合(collection)架構,該實例管理了很多對象,可以想象成一個保管有大量保險箱的房間。
java.lang.ThreadLocal類的方法:
- public void set()
該方法會檢查當前調用線程,默認以該線程的Thread.currentThread()值作為鍵,來保存指定的值。
- public Object get()
該方法會檢查當前調用線程,默認以該線程的Thread.currentThread()值作為鍵,獲取保存指定的值。
二、模式案例
TSLog類:
package Entity;import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; // 實際執行記錄日志的類,每個線程都會擁有一個該類的實例 public class TSLog {private PrintWriter writer = null;public TSLog(String fileName) {try {writer = new PrintWriter(new FileWriter(fileName));} catch (IOException e) {e.printStackTrace();}}public void println(String e) {writer.println(e);}public void close() {writer.println("****** End of log");writer.close();} }Log類:
package Entity;public class Log {private static final ThreadLocal<TSLog> TS_LOG_THREAD_LOCAL = new ThreadLocal<>();public static void println(String s) {getTSLog().println(s);}public static void close() {getTSLog().close();}private static TSLog getTSLog() {TSLog tsLog = TS_LOG_THREAD_LOCAL.get();if (tsLog == null) {tsLog = new TSLog(Thread.currentThread() + "-log.txt");TS_LOG_THREAD_LOCAL.set(tsLog);}return tsLog;} }ClientThread類:
package Entity;public class ClientThread extends Thread{public ClientThread(String name) {super(name);}@Overridepublic void run() {System.out.println(getName() + " BEGIN");for (int i = 0; i < 10; i++) {Log.println("i=" + i);try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}}Log.close();System.out.println(getName() + " END");} }main類:
import Entity.ClientThread;public class Demo2 {public static void main(String[] args) {new ClientThread("Alice").start();new ClientThread("Bobby").start();new ClientThread("Chris").start();} }?
三、模式講解
Thread-Specific Storage模式的角色如下:
- Client(委托人)參與者
Client參與者會將工作委托給TSObjectProxy參與者。(案例中的ClientThread類就是Client)
- TSObjectProxy(線程獨有對象的代理者)參與者
TSObjectProxy參與者會處理多個Client委托的工作。(案例中的Log類就是TSObjectProxy)
- TSObjectCollection(線程獨有對象的集合)參與者
(案例中的java.lang.ThreadLocal類就是TSObjectCollection)
- TSObject(線程獨有的對象)參與者
TSObject存放線程所特有的信息,TSObject實例的方法只會由單線程調用,由TSObjectCollection管理,每個線程獨都擁有獨自的TSObject實例。(案例中的TSLog類就是TSObject)
四、ThreadLocal的原理
ThreadLocal類主要有四個方法:
1、初始化返回值的方法:
該方法實現只返回null,并且修飾符為protected,很明顯,如果用戶想返回初始值不為null,則需要重寫該方法;
protected T initialValue() {return null;}2、get方法,獲取線程本地副本變量
public T get() {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null) {ThreadLocalMap.Entry e = map.getEntry(this);if (e != null) {@SuppressWarnings("unchecked")T result = (T)e.value;return result;}}return setInitialValue();}3、set方法,設置線程本地副本變量
public void set(T value) {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null)map.set(this, value);elsecreateMap(t, value);}4、remove方法,移除線程本地副本變量
public void remove() {ThreadLocalMap m = getMap(Thread.currentThread());if (m != null)m.remove(this);}如果需要我們自己來設計ThreadLocal對象,那么,一般的實現思路:
設計一個線程安全的Map,key就是當前線程對象,Value就是線程本地變量的值。
然而,JDK的實現思路:
讓每個Thread對象,自身持有一個Map,這個Map的Key就是當前ThreadLocal對象,Value是本地線程變量值。相對于加鎖的實現方式,這樣做可以提升性能,其實是一種以空間換時間的思路。
ThreadLocal類有一個getMap()方法,其實就是返回Thread對象自身的Map——threadLocals。
ThreadLocalMap getMap(Thread t) {return t.threadLocals;}threadLocals是一種ThreadLocal.ThreadLocalMap類型的數據結構,作為內部類定義在ThreadLocal類中,其內部采用一種WeakReference的方式保存鍵值對。
總結
以上是生活随笔為你收集整理的深入解析J.U.C并发包(十五)—— Thread - Specific Storage(ThreadLocal)模式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 插入参考文献时,本该显示为[1],但显示
- 下一篇: 云计算与虚拟化是什么关系