java併發編程 簡單講解,看不懂算我的……(一)ThreadLocal

ThreadLocal是什麼

java併發編程 簡單講解,看不懂算我的……(一)ThreadLocal

ThreadLocal是什麼呢?其實ThreadLocal並非是一個線程的本地實現版本,它並不是一個Thread,而是threadlocalvariable(線程局部變量)。也許把它命名為ThreadLocalVar更加合適。ThreadLocal功能非常簡單,就是為每一個使用該變量的線程都提供一個變量值的副本,是Java中一種較為特殊的線程綁定機制,是每一個線程都可以獨立地改變自己的副本,而不會和其它線程的副本衝突。

從線程的角度看,每個線程都保持一個對其線程局部變量副本的隱式引用,只要線程是活動的並且ThreadLocal實例是可訪問的;在線程消失之後,其線程局部實例的所有副本都會被垃圾回收(除非存在對這些副本的其他引用)。

通過ThreadLocal存取的數據,總是與當前線程相關,也就是說,JVM 為每個運行的線程,綁定了私有的本地實例存取空間,從而為多線程環境常出現的併發訪問問題提供了一種隔離機制。

ThreadLocal的接口方法

void set(Object value)

    • 設置當前線程的線程局部變量的值;

public Object get()

    • 該方法返回當前線程所對應的線程局部變量;

public void remove()

    • 將當前線程局部變量的值刪除,目的是為了減少內存的佔用,該方法是JDK 5.0新增的方法。需要指出的是,當線程結束後,對應該線程的局部變量將自動被垃圾回收,所以顯式調用該方法清除線程的局部變量並不是必須的操作,但它可以加快內存回收的速度;

protected Object initialValue()

  • 返回該線程局部變量的初始值,該方法是一個protected的方法,顯然是為了讓子類覆蓋而設計的。這個方法是一個延遲調用方法,在線程第1次調用get()或set(Object)時才執行,並且僅執行1次。ThreadLocal中的默認實現直接返回一個null

  這裡注意,ThreadLocal中是有一個Map,但這個Map不是我們平時使用的Map,而是ThreadLocalMap,ThreadLocalMap是ThreadLocal的一個內部類,不對外使用的。當使用ThreadLocal存值時,首先是獲取到當前線程對象,然後獲取到當前線程本地變量Map,最後將當前使用的ThreadLocal和傳入的值放到Map中,也就是說ThreadLocalMap中存的值是[ThreadLocal對象, 存放的值],這樣做的好處是,每個線程都對應一個本地變量的Map,所以一個線程可以存在多個線程本地變量

一個TheadLocal實例

/**

*

* @ClassName: SequenceNumber

* @author xingle

* @date 2015-3-9 上午9:54:23

*/

public class SequenceNumber {

//①通過匿名內部類覆蓋ThreadLocal的initialValue()方法,指定初始值

private static ThreadLocal<Integer> seqNum = new ThreadLocal<Integer>(){

public Integer initialValue(){

return 0;

}

};

//②獲取下一個序列值

public int getNextNum(){

seqNum.set(seqNum.get()+1);

return seqNum.get();

}

public static void main(String[] args){

SequenceNumber sn = new SequenceNumber();

//③ 3個線程共享sn,各自產生序列號

TestClient t1 = new TestClient(sn);

TestClient t2 = new TestClient(sn);

TestClient t3 = new TestClient(sn);

t1.start();

t2.start();

t3.start();

}

private static class TestClient extends Thread{

private SequenceNumber sn;

public TestClient(SequenceNumber sn){

this.sn = sn;

}

public void run(){

//④每個線程打出3個序列值

for (int i = 0 ;i<3;i++){

System.out.println("thread["+Thread.currentThread().getName()+"] sn["+sn.getNextNum()+"]");

}

}

}

}

 通常我們通過匿名內部類的方式定義ThreadLocal的子類,提供初始的變量值,如①處所示。TestClient線程產生一組序列號,在③處,我們生成3個TestClient,它們共享同一個SequenceNumber實例。運行以上代碼,在控制檯上輸出以下的結果:

java併發編程 簡單講解,看不懂算我的……(一)ThreadLocal

  每個線程所產生的序號雖然都共享同一個Sequence Number實例,但它們並沒有發生相互干擾的情況,而是各自產生獨立的序列號,這是因為我們通過ThreadLocal為每一個線程提供了單獨的副本。

相關推薦

推薦中...