国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發(fā)設計 > 正文

ThreadLocal模式的原理

2019-11-14 14:52:04
字體:
來源:轉載
供稿:網友

  在JDK的早期版本中,提供了一種解決多線程并發(fā)問題的方案:java.lang.ThreadLocal類。ThreadLocal類在維護變量時,實際使用了當前線程(Thread)中的一個叫做ThreadLocalMap的獨立副本,每個線程可以獨立修改屬于自己的副本而不會互相影響,從而隔離了線程和線程,避免了線程訪問實例變量發(fā)生沖突的問題。

  ThreadLocal本身并不是一個線程,而是通過操作當前線程中的一個內部變量來達到與其他線程隔離的目的。之所以取名為ThreadLocal,所期望表達的含義是其操作的對象是線程的一個本地變量。

 

Thread.java

public class Thread implements Runnable {    // 這里省略了許多其他的代碼    ThreadLocal.ThreadLocalMap threadLocals = null;}

 

ThreadLocal.java

public class ThreadLocal<T> {    // 這里省略了許多其他代碼      // 將value 的值保存于當前線程的本地變量中      public void set(T value) {        // 獲取當前線程         Thread t = Thread.currentThread();        // 調用getMap 方法獲得當前線程中的本地變量ThreadLocalMap         ThreadLocalMap map = getMap(t);        // 如果ThreadLocalMap 已存在,直接使用        if (map != null)            // 以當前的ThreadLocal 的實例作為key,存儲于當前線程的                     // ThreadLocalMap 中,如果當前線程中定義了多個不同的ThreadLocal                     // 的實例,則它們會作為不同key 進行存儲而不會互相干擾                     map.set(this, value);        else            // 如果ThreadLocalMap 不存在,則為當前線程創(chuàng)建一個新的             createMap(t, value);    }    // 獲取當前線程中以當前ThreadLocal 實例為key 的變量值    public T get() {        // 獲取當前線程            Thread t = Thread.currentThread();        // 獲取當前線程中的ThreadLocalMap            ThreadLocalMap map = getMap(t);        if (map != null) {            // 獲取當前線程中以當前ThreadLocal 實例為key 的變量值            ThreadLocalMap.Entry e = map.getEntry(this);            if (e != null)                return (T) e.value;        }        // 當map 不存在時,設置初始值        return setInitialValue();    }    // 從當前線程中獲取與之對應的ThreadLocalMap     ThreadLocalMap getMap(Thread t) {        return t.threadLocals;    }    // 創(chuàng)建當前線程中的ThreadLocalMap     void createMap(Thread t, T firstValue) {        // 調用構造函數生成當前線程中的ThreadLocalMap         t.threadLocals = new ThreadLocalMap(this, firstValue);    }    // ThreadLoaclMap 的定義        static class ThreadLocalMap {        //這里省略了許多代碼    }}

 

  • ThreadLocalMap變量屬于線程的內部屬性,不同的線程擁有完全不同的ThreadLo-calMap變量。
  • 線程中的ThreadLocalMap變量的值是在ThreadLocal對象進行set或者get操作時創(chuàng)建的。
  • 在創(chuàng)建ThreadLocalMap之前,會首先檢查當前線程中的ThreadLocalMap變量是否已經存在,如果不存在則創(chuàng)建一個;如果已經存在,則使用當前線程已創(chuàng)建的ThreadLo-calMap。
  • 使用當前線程的ThreadLocalMap的關鍵在于使用當前的ThreadLocal的實例作為key進行存儲。

 

ThreadLocal模式至少從兩個方面完成了數據訪問隔離,即橫向隔離和縱向隔離。

  • 縱向隔離——線程與線程之間的數據訪問隔離。這一點由線程的數據結構保證。因為每個線程在進行對象訪問時,訪問的都是各個線程自己的ThreadLocalMap。  
  • 橫向隔離——同一個線程中,不同的Thread-Local實例操作的對象之間相互隔離。這一點由ThreadLocalMap在存儲時采用當前ThreadLocal的實例作為key來保證。

 

深入比較ThreadLocal模式與synchronized關鍵字

  • ThreadLocal是一個Java類,通過對當前線程中的局部變量的操作來解決不同線程的變量訪問的沖突問題。所以,ThreadLocal提供了線程安全的共享對象機制,每個線程都擁有其副本。
  • Java中的synchronized是一個保留字,它依靠JVM的鎖機制來實現臨界區(qū)的函數或者變量在訪問中的原子性。在同步機制中,通過對象的鎖機制保證同一時間只有一個線程訪問變量。此時,被用作“鎖機制”的變量是多個線程共享的。
  • 同步機制(synchronized關鍵字)采用了“以時間換空間”的方式,提供一份變量,讓不同的線程排隊訪問。而ThreadLocal采用了“以空間換時間”的方式,為每一個線程都提供一份變量的副本,從而實現同時訪問而互不影響。

要完成ThreadLocal模式,其中最關鍵的地方就是創(chuàng)建一個任何地方都可以訪問到的ThreadLocal實例。而這一點,我們可以通過類變量來實現,這個用于承載類變量的類就被視作是一個共享環(huán)境。

 

public class Counter {    // 新建一個靜態(tài)的ThreadLocal 變量,并通過get 方法將其變?yōu)橐粋€可訪問的對象     PRivate static ThreadLocal<Integer> counterContext = new            ThreadLocal<Integer>() {                protected synchronized Integer initialValue() {                    return 10;                }            };    // 通過靜態(tài)的get 方法訪問ThreadLocal 中存儲的值      public static Integer get() {        return counterContext.get();    }    // 通過靜態(tài)的set 方法將變量值設置到ThreadLocal 中      public static void set(Integer value) {        counterContext.set(value);    }    // 封裝業(yè)務邏輯,操作存儲于ThreadLocal 中的變量    public static Integer getNextCounter() {        counterContext.set(counterContext.get() + 1);        return counterContext.get();    }}

 

public class ThreadLocalTest extends Thread {    public void run() {        for (int i = 0; i < 3; i++) {            System.out.println("Thread[" + Thread.currentThread().getName() + "],counter=" + Counter.getNextCounter());        }    }}

 

public class Test {    public static void main(String[] args) throws Exception {        ThreadLocalTest testThread1 = new ThreadLocalTest();        ThreadLocalTest testThread2 = new ThreadLocalTest();        ThreadLocalTest testThread3 = new ThreadLocalTest();        testThread1.start();        testThread2.start();        testThread3.start();    }}

 

我們來運行一下上面的代碼,并看看輸出結果:

Thread[Thread-2],counter=11Thread[Thread-2],counter=12Thread[Thread-2],counter=13Thread[Thread-0],counter=11Thread[Thread-0],counter=12Thread[Thread-0],counter=13Thread[Thread-1],counter=11Thread[Thread-1],counter=12Thread[Thread-1],counter=13

 

ThreadLocal模式最合適的使用場景:在同一個線程的不同開發(fā)層次中共享數據。

ThreadLocal模式的兩個主要步驟:  

  • 建立一個類,并在其中封裝一個靜態(tài)的ThreadLocal變量,使其成為一個共享數據環(huán)境。  
  • 在類中實現訪問靜態(tài)ThreadLocal變量的靜態(tài)方法(設值和取值)。

 

 

未完待續(xù)...


發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 岳西县| 阿巴嘎旗| 济宁市| 寻乌县| 论坛| 连江县| 万荣县| 隆昌县| 宜良县| 新野县| 兰坪| 株洲县| 达拉特旗| 吴忠市| 响水县| 郁南县| 扎赉特旗| 金沙县| 健康| 泾阳县| 辉县市| 中江县| 赣州市| 玛多县| 工布江达县| 清河县| 丹东市| 连山| 高台县| 阿克苏市| 德清县| 阳原县| 洛浦县| 辽源市| 贵港市| 乌拉特前旗| 射洪县| 兴山县| 临江市| 洞头县| 遵化市|