生活随笔
收集整理的這篇文章主要介紹了
第11章-ThreadSpecificStorage
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
文章目錄 11.1 Thread-Specific Storage模式 11.2 java.lang.ThreadLocal 11.2.1 java.lang.ThreadLocal 就是儲物間 11.2.2 java.lang.ThreadLocal 與泛型 11.5 Thread-Specific Storage模式中的角色 11.5.1 Client(委托者) 11.5.2 TSObjectProxy(線程特有的對象的代理人) 11.5.3 TSObjectCollection(線程特有的對象的集合) 11.5.4 TSObject(線程特有的對象) 11.5.5 類圖與時序圖 11.6 拓展思路的要點 11.6.1 局部變量與 java.lang.ThreadLocal 類 11.6.2 保存線程特有的信息的位置 11.6.2.1 在線程外保存線程特有的信息 11.6.2.2 在線程內(nèi)保存線程特有的信息 11.6.2.3 總結(jié) 11.6.3 不必擔心其他線程訪問 11.6.4 吞吐量的提高很大程序上取決于實現(xiàn)方式 11.8 基于角色與基于任務 11.8.1 主體與客體 11.8.2 基于角色的考慮方式 11.8.3 基于任務的考慮方式
11.1 Thread-Specific Storage模式
有一個儲物間,里面并排擺放著許多儲物柜。一個人拿著自己的鑰匙進入了儲物間,出來時手上拿著自己的行李。別人也拿著自己的鑰匙進入了儲物間。但是,雖然進人的是同一個儲物間,打開的當然是另外一個儲物柜。使用者都會從各自的儲物柜中取出自己的行李。 Specific是 “特定的” 的意思,Storage是儲存柜、存儲裝置的意思。因此,所謂 Thread-Specific Storage 就是 “每個線程特有的存儲柜”、“為每個線程準備的存儲空間 ” 的意思。 Thread-Specific Storage模式是一種即使只有一個入口,也會在內(nèi)部為每個線程分配特有的存儲空間的模式。
11.2 java.lang.ThreadLocal
11.2.1 java.lang.ThreadLocal 就是儲物間
將 Java.lang.ThreadLocal 的實例當作一種集合可能會有助于大家理解它。也就是說,一個ThreadLocal的實例會管理多個對象 。 ThreadLocal 類的 set 方法用于將通過參數(shù)接收的實例與調(diào)用該方法的線程(當前線程)對應并存儲起來。這里存儲的對象可以通過get方法獲取。set方法中沒有表示線程的參數(shù)。set方法會先查詢當前線程 (即表達式Thread.currentThread()的值),然后以它作為鍵來存儲實例。 ThreadLocal 類的 get 方法用于獲取與調(diào)用 get 方法的線程(當前線程)對應的實例。該線程之前通過 set 方法存儲的實例就是 get 方法的返回值。如果之前一次都還沒有調(diào)用過 set 方法,則 get方法的返回值為null。
11.2.2 java.lang.ThreadLocal 與泛型
java.lang.ThreadLocal是一個泛型類,可以通過參數(shù)的類型來指定要存儲的對象的類型。ThreadLocal 類的聲明大致如下:
public class ThreadLocal < T>
{ public void set
( T value
) { . . . } public T get
( ) { . . . } . . .
}
即通過 ThreadLocal<T> 的 T 指定的類型就是 set 方法的參數(shù)的類型以及 get 方法的返回值的類型。
11.5 Thread-Specific Storage模式中的角色
11.5.1 Client(委托者)
Client 角色將處理委托給 TSObjectProxy 角色。一個 TSObjectProxy 角色會被多個 Client 角色使用。
11.5.2 TSObjectProxy(線程特有的對象的代理人)
TSObjectProxy 角色會執(zhí)行多個Client角色委托給它的處理。 首先,TSObjectProxy 角色使用 TSObjectCollection 角色獲取與 Client 角色對應的TSObject 角色。接著,它將處理委托給TSObject角色。
11.5.3 TSObjectCollection(線程特有的對象的集合)
TSObjectCollection 角色有一張 Client 角色與 TSObject 角色之間的對應表 。當 getTSObject()方法被調(diào)用后,它會去查看對應表,返回與 Client 角色相對應的 TSObject 角色。另外,當setTSObject()方法被調(diào)用后,它會將 Client 角色與 TSObject 角色之間的鍵值對應關系設置到對應表中。 在示例程序中,由 Java.lang.ThreadLocal 類扮演此角色。
11.5.4 TSObject(線程特有的對象)
TSObject 角色中保存著線程特有的信息。 TSObject 角色由 TSObjectCollection 角色管理。TSObject角色的方法只會被單線程調(diào)用。
11.5.5 類圖與時序圖
11.6 拓展思路的要點
11.6.1 局部變量與 java.lang.ThreadLocal 類
線程本來都是有自己特有的存儲空間的,即用于保存方法的局部變量的棧。方法中定義的局部變量屬于該線程特有,其他線程無法訪問它們。但是,這些變量在方法調(diào)用結(jié)束后就會消失 。而 ThreadLocal 則與方法調(diào)用無關,它是一個用于為線程分配特有的存儲空間的類 。
11.6.2 保存線程特有的信息的位置
線程特有的信息的 “保存位置” 有以下兩種: 線程外(thread-external) 線程內(nèi)(thread-internal)
11.6.2.1 在線程外保存線程特有的信息
示例程序中的線程特有的信息是 TSLog 的實例,而所有的 TSLog 的實例都被保存在 Log 類中的Java.lang.ThreadLocal 的實例中。 ThreadLocal 的實例就是儲物間,各個線程的儲物柜都被集中在這個儲物間內(nèi)。線程并不會背著儲物柜四處走動。像這樣,將線程特有的信息保存在線程外部的方法稱為 “線程外”。 將線程特有的信息保存在線程外部的方法不需要修改既有的表示線程的類 ,所以可以適用于任何線程。但是,隨之而來的是表示線程的類的代碼可能會變得難以理解 。這是因為,僅僅查看表示線程的類的源代碼是無法知道其他類中是否還保存著線程特有的信息的。
11.6.2.2 在線程內(nèi)保存線程特有的信息
假設我們編寫了一個Thread類的子類 MyThread。如果在MyThread中聲明字段 ,該字段就是線程特有的信息。這就是在線程內(nèi)保存線程特有的信息。采用這種方法時,通過閱讀線程的源代碼可以很容易地知道線程有哪些特有的信息。但是,隨之而來的是當以后需要增加線程特有的信息時,必須修改MyThread類。 我們使用 “有” 這個詞的時候,有時候表示的是 “擁有” 的意思,有時候也表示實際地 “在手上” 的意思。 例如 “有錢” 這個詞并不一定表示錢就確實地 “在手中” 。這是因為,有可能錢被存放在了諸如銀行 這樣的TSObjectCollection角色里面。
11.6.2.3 總結(jié)
在線程外部保存線程特有的信息的方法:雖然有錢,但是錢不在手中 在線程內(nèi)部保存線程特有的信息的方法:錢確實地在自己手中
11.6.3 不必擔心其他線程訪問
Thread-Specific Storage 模式為我們提供了一種以線程作為鍵,讓每個線程只能訪問它特有的對象 的機制。 允許被多個線程訪問的是 TSObjectProxy 角色。接著,TSObjectProxy角色(使用TSObjectCollection角色)將 TSObject 角色分配給了各個線程。在Thread-Specific Storage模式中,在多個線程之間被共享的部分只到TSObjectProxy角色為止 ,實際的處理是在將 TSObject 角色分配給每個線程之后才執(zhí)行的。
11.6.4 吞吐量的提高很大程序上取決于實現(xiàn)方式
Thread-Specific Storage 模式并沒有執(zhí)行互斥處理。因此,這很容易讓人誤解為與使用Single Threaded Execution模式相比,此時的吞吐量會有所提高。 但是事實上可能 TSObjectCollection 角色中執(zhí)行了隱藏的互斥處理 。此外,每次通過 TSObjectProxy 角色調(diào)用方法時,使用 TSObjectCollection 角色來獲取 TSObject 角色都會產(chǎn)生額外的性能開銷。 與強調(diào)吞吐量相比,Thread-Specific Storage 模式更看重如下所示的可復用性: 不改變結(jié)構(gòu)即可實現(xiàn)程序 沒有顯式地執(zhí)行互斥處理 ,所以編程時犯錯的可能性較小
11.8 基于角色與基于任務
11.8.1 主體與客體
要想組裝塑料模型,以下二者缺一不可:
只有組裝塑料模型的人或是只有塑料模型套件時,無法完成塑料模型。
同理,假設我們需要讓線程去完成一項工作,那么以下二者缺一不可:
無論是組裝塑料模型,還是讓線程進行工作,以下二者缺一不可:
在設計多線程程序時,根據(jù)以 “主體” 為主還是以 “客體” 為主的不同產(chǎn)生了以下兩種方式:
11.8.2 基于角色的考慮方式
所謂基于角色,一言以蔽之即 “線程最偉大” 的方式。 基于角色的方式即在表示線程的實例中保存進行工作所必需的信息 (上下文、狀態(tài))。這樣可以減少和減輕線程之間的交互信息量 。一個線程會使用從其他線程接收到的信息來執(zhí)行處理,改變自己的內(nèi)部狀態(tài)。通常,我們稱這樣的線程為角色 。 假設我們要編寫一段程序,在這段程序中定義了一個Thread類的子類,然后在子類中定義了一個字段,并在這個字段中保存與工作相關的信息。這樣,我們就完成了一個 “小角色”:
class Actor extends Thread\
{ 角色的內(nèi)部狀態(tài)
public void run
( ) { 循環(huán)地從外部接收并執(zhí)行任務,改變內(nèi)部狀態(tài)
}
}
11.8.3 基于任務的考慮方式
所謂基于任務,一言以蔽之即 “任務最偉大” 的方式。 基于任務的方式不在線程中保存信息(上下文、狀態(tài))。在這種方式下,這些信息不保存在線程中,而是保存在線程之間交互的實例中 。而且,不僅是數(shù)據(jù),連用于執(zhí)行請求的方法都定義在其中。像這樣在線程之間交互的實例可以稱為消息、請求或是命令。這里我們暫且稱其為任務 。 由于任務中保存了足夠的信息,所以任何線程執(zhí)行該任務都沒有問題 。可以說,這是一種富(rich)任務往來于輕線程之間 的方式。 使用該方式的一個典型的模式是Worker Thread模式。 我們?yōu)閹в行畔⒌念惣由?implements Runnable ,然后實現(xiàn)run方法后,線程就可以執(zhí)行該類了。這樣就編寫完成了一個 “小任務”。將編寫完成的任務傳遞給線程后 ,線程就會進行工作:
class Task implements Runnable
{ 進行工作所必須的信息
public void run
( ) { 工作的處理內(nèi)容
}
}
總結(jié)
以上是生活随笔 為你收集整理的第11章-ThreadSpecificStorage 的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔 推薦給好友。