1. 程式人生 > >Java多執行緒設計模式(6)兩階段終止模式

Java多執行緒設計模式(6)兩階段終止模式

一  Thread-Specific Storage Pattern

  Thread-Specific Storage Pattern指的就是執行緒獨有的儲藏庫,針對每個執行緒提供記憶體空間的意義。這種模式只有一個入口,但是內部會對每個執行緒提供特有的儲存空間。

  Thread-Specific Storage Pattern的所有參與者:

  1,Client參與者,提出具體工作的,將該具體工作委託給TSObjectProxy參與者。

  2,TSObjectProxy參與者,這個主要是接受工作請求的,它會處理多個Client的工作,它一般都包括了TSObjectCollection。一般都是先使用TSObjectCollection參與者,取得Client參與者所對應的TSObject參與者,並將Client具體的工作委託給TSObject參與者。

  3,TSObjectCollection參與者,這個主要就是執行緒獨有物件的集合,它利用執行緒鍵值對來儲存著執行Client參與者執行緒所對應的TSObject參與者。一般都是利用ThreadLocal來實現。

  4,TSObject參與者,執行緒獨有的物件,存放著執行緒特有的資訊,儘管會為多個執行緒使用,但是不需要利用synchronized來進行互斥操作。

  TSObject參與者與TSObjectProxy參與者具有相同的介面。

  具體的模式如下圖所示。雖然多個不同的ClientThread來請求同一個物件Log即TSObjectProxy參與者,但是Log會為每個請求執行緒利用ThreadLocal來分配獨立的TSLog物件。所有執行緒所共享的是TSObjectProxy參與者。

  

關於ThreadLocal小講:

   每一個執行緒都擁有自己獨立的儲存空間,也就是方法區域性變數的堆疊,在方法裡分配的區域性變數都是執行緒所獨有的,但是這些變數一退出方法就會消失了。ThreadLocal則是與方法呼叫無關,它為執行緒分配特有空間。

   ThreadLocal例項如一個保管箱間,它通過執行緒鍵值對來儲存與執行緒特定的資訊。每個執行緒的保管箱,都放置在ThreadLocal中。

   ThreadLocal該類提供了執行緒區域性變數。ThreadLocal的區域性變數在被多個執行緒使用時候,每個執行緒只能拿到該變數的一個副本。

   在ThreadLocal型別的變數內部有個ThreadLocalMap,它提供了一個登錄檔來註冊與當前執行緒相關的資訊,ThreadLocal型別的變數對外部表現是一個,但是內部確實管理著一群物件的集合。

   在利用get與set的時候,都會在兩個方法體中首先獲取Thread t = Thread.currentThread();,然後在該執行緒的內部進行操作。不用擔心其他執行緒對於該執行緒的破壞訪問。在使用兩個方法的時候務必要分清是屬於那個執行緒中的操作。

   在這個模式中,客戶端執行緒所共享的是TSObjectProxy參與者,但是實際的工作則是在TSObject參與者分配給相應的執行緒後才進行的,就是利用TSObjectProxy參與者來分配不被共享的TSObject參與者。對於TSObject完全不用做任何的互斥synchronized操作。

程式碼示例:

僅僅列出TSObjectProxy的架構模式

Log代表了TSObjectProxy參與者,供多個執行緒進行訪問,最後將具體的操作委託給TSObject

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 package whut.specificstorage; //負責產生保管箱間的類 public class Log { //首先利用static final修飾 //保證了所有訪問該類的執行緒都只使用一個唯一的且不變的保管箱間。 private static final ThreadLocal tsLogCollections=new ThreadLocal(); //不用使用synchronized,因為在使用get和set時候,會欄位判別當前所屬的執行緒 //取得當前執行緒特有的Log private static TSLog getTSLog() { TSLog tsLog=(TSLog)tsLogCollections.get(); //如果執行緒是第一次呼叫,就建立新資料夾以及註冊log if(tsLog==null) { tsLog=new TSLog(Thread.currentThread().getName()+"-log.txt"); tsLogCollections.set(tsLog); } return tsLog; } //加入一條LOG public static void