摘要:案例中的類就是線程獨(dú)有對(duì)象的代理者參與者參與者會(huì)處理多個(gè)委托的工作。然而,的實(shí)現(xiàn)思路讓每個(gè)對(duì)象,自身持有一個(gè),這個(gè)的就是當(dāng)前對(duì)象,是本地線程變量值。
一、定義
Thread-Specific Storage就是“線程獨(dú)有的存儲(chǔ)庫”,該模式會(huì)對(duì)每個(gè)線程提供獨(dú)有的內(nèi)存空間。
java.lang.ThreadLocal類提供了該模式的實(shí)現(xiàn),ThreadLocal的實(shí)例是一種集合(collection)架構(gòu),該實(shí)例管理了很多對(duì)象,可以想象成一個(gè)保管有大量保險(xiǎn)箱的房間。
java.lang.ThreadLocal類的方法:
public void set()
該方法會(huì)檢查當(dāng)前調(diào)用線程,默認(rèn)以該線程的Thread.currentThread()值作為鍵,來保存指定的值。
public Object get()
該方法會(huì)檢查當(dāng)前調(diào)用線程,默認(rèn)以該線程的Thread.currentThread()值作為鍵,獲取保存指定的值。
二、模式案例TSLog類:
//實(shí)際執(zhí)行記錄日志的類,每個(gè)線程都會(huì)擁有一個(gè)該類的實(shí)例 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 s) { writer.println(s); } public void close() { writer.println("==== End of log ===="); writer.close(); } }
Log類:
public class Log { private static final ThreadLocaltsLogCollection = new ThreadLocal (); public static void println(String s) { getTSLog().println(s); } public static void close() { getTSLog().close(); } private static TSLog getTSLog() { TSLog tsLog = (TSLog) tsLogCollection.get(); if (tsLog == null) { tsLog = new TSLog(Thread.currentThread().getName() + "-log.txt"); tsLogCollection.set(tsLog); } return tsLog; } }
ClientThread類:
public class ClientThread extends Thread { public ClientThread(String name) { super(name); } public 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) { } } Log.close(); System.out.println(getName() + " END"); } }
執(zhí)行:
Alice、Bobby、Chris三個(gè)線程調(diào)用Log類的同一個(gè)方法,但實(shí)際上每個(gè)線程都擁有獨(dú)自的TSLog實(shí)例。
public class Main { public static void main(String[] args) { new ClientThread("Alice").start(); new ClientThread("Bobby").start(); new ClientThread("Chris").start(); } }三、模式講解
Thread-Specific Storage模式的角色如下:
Client(委托人)參與者
Client參與者會(huì)將工作委托給TSObjectProxy參與者。(案例中的ClientThread類就是Client)
TSObjectProxy(線程獨(dú)有對(duì)象的代理者)參與者
TSObjectProxy參與者會(huì)處理多個(gè)Client委托的工作。(案例中的Log類就是TSObjectProxy)
TSObjectCollection(線程獨(dú)有對(duì)象的集合)參與者
(案例中的java.lang.ThreadLocal類就是TSObjectCollection)
TSObject(線程獨(dú)有的對(duì)象)參與者
TSObject存放線程所特有的信息,TSObject實(shí)例的方法只會(huì)由單線程調(diào)用,由TSObjectCollection管理,每個(gè)線程都擁有獨(dú)立的TSObject實(shí)例。(案例中的TSLog類就是TSObject)
四、ThreadLocal的原理ThreadLocal類主要有四個(gè)方法:
1、初始化返回值的方法:
該方法實(shí)現(xiàn)只返回 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) { T result = (T)e.value; return result; } } return setInitialValue(); }
3、set方法,設(shè)置線程本地副本變量
public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); }
4、remove方法,移除線程本地副本變量
public void remove() { ThreadLocalMap m = getMap(Thread.currentThread()); if (m != null) m.remove(this); }
如果需要我們自己來設(shè)計(jì)ThreadLocal對(duì)象,那么,一般的實(shí)現(xiàn)思路:
設(shè)計(jì)一個(gè)線程安全的Map,key就是當(dāng)前線程對(duì)象,Value就是線程本地變量的值。
然而,JDK的實(shí)現(xiàn)思路:
讓每個(gè)Thread對(duì)象,自身持有一個(gè)Map,這個(gè)Map的Key就是當(dāng)前ThreadLocal對(duì)象,Value是本地線程變量值。相對(duì)于加鎖的實(shí)現(xiàn)方式,這樣做可以提升性能,其實(shí)是一種以時(shí)間換空間的思路。
ThreadLocal類有個(gè)getMap()方法,其實(shí)就是返回Thread對(duì)象自身的Map——threadLocals。
ThreadLocalMap getMap(Thread t) { return t.threadLocals; }
threadLocals是一種ThreadLocal.ThreadLocalMap類型的數(shù)據(jù)結(jié)構(gòu),作為內(nèi)部類定義在ThreadLocal類中,其內(nèi)部采用一種WeakReference的方式保存鍵值對(duì)。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/71507.html
摘要:具體怎么實(shí)現(xiàn)的呢,思想其實(shí)特別簡單,我們?cè)谏钊肜斫庵械淖兞可弦晃牡淖詈笥刑崞疬^,就是創(chuàng)建一個(gè)全局字典,然后將線程或者協(xié)程標(biāo)識(shí)符作為,相應(yīng)線程或協(xié)程的局部數(shù)據(jù)作為。 在上篇我們看到了 ThreadLocal 變量的簡單使用,中篇對(duì)python中 ThreadLocal 的實(shí)現(xiàn)進(jìn)行了分析,但故事還沒有結(jié)束。本篇我們一起來看下Werkzeug中ThreadLocal的設(shè)計(jì)。 Werkzeug...
摘要:并發(fā)設(shè)計(jì)模式一模式的使用表示線程本地存儲(chǔ)模式。為不同的任務(wù)創(chuàng)建不同的線程池,這樣能夠有效的避免死鎖問題。兩階段終止,即將線程的結(jié)束分為了兩個(gè)階段,第一個(gè)階段是一個(gè)線程向另一個(gè)線程發(fā)送終止指令,第二個(gè)階段是線程響應(yīng)終止指令。 Java 并發(fā)設(shè)計(jì)模式 一、Thread Local Storage 模式 1. ThreadLocal 的使用 Thread Local Storage 表示線程...
摘要:并沒有提供語言級(jí)的線程局部變量,而是在類庫里提供了線程局部變量的功能,也就是這次的主角類。 Yuicon 轉(zhuǎn)載請(qǐng)注明原創(chuàng)出處,謝謝! 序 在多線程環(huán)境下,訪問非線程安全的變量時(shí)必須進(jìn)行線程同步,例如使用synchronized方式訪問HashMap實(shí)例。但是同步訪問會(huì)降低并發(fā)性,影響系統(tǒng)性能。這時(shí)候就可以用空間換時(shí)間,如果我們給每個(gè)線程都分配一個(gè)獨(dú)立的變量,就可以用非同步的方式使用非...
摘要:基本在項(xiàng)目開發(fā)中基本不會(huì)用到但是面試官是比較喜歡問這類問題的所以還是有必要了解一下該類的功能與原理的是什么是一個(gè)將在多線程中為每一個(gè)線程創(chuàng)建單獨(dú)的變量副本的類當(dāng)使用來維護(hù)變量時(shí)會(huì)為每個(gè)線程創(chuàng)建單獨(dú)的變量副本避免因多線程操作共享變量而導(dǎo)致的數(shù) ThreadLocal基本在項(xiàng)目開發(fā)中基本不會(huì)用到, 但是面試官是比較喜歡問這類問題的;所以還是有必要了解一下該類的功能與原理的. Thread...
摘要:我們知道多線程環(huán)境下,每一個(gè)線程均可以使用所屬進(jìn)程的全局變量。在線程中使用局部變量則不存在這個(gè)問題,因?yàn)槊總€(gè)線程的局部變量不能被其他線程訪問。 我們知道多線程環(huán)境下,每一個(gè)線程均可以使用所屬進(jìn)程的全局變量。如果一個(gè)線程對(duì)全局變量進(jìn)行了修改,將會(huì)影響到其他所有的線程。為了避免多個(gè)線程同時(shí)對(duì)變量進(jìn)行修改,引入了線程同步機(jī)制,通過互斥鎖,條件變量或者讀寫鎖來控制對(duì)全局變量的訪問。 只用全局變...
閱讀 3640·2023-04-26 02:07
閱讀 3150·2021-09-22 15:55
閱讀 2534·2021-07-26 23:38
閱讀 3119·2019-08-29 15:16
閱讀 2008·2019-08-29 11:16
閱讀 1746·2019-08-29 11:00
閱讀 3583·2019-08-26 18:36
閱讀 3165·2019-08-26 13:32