1. 程式人生 > >Java併發程式設計 看不懂算我的!

Java併發程式設計 看不懂算我的!

ThreadLocal是什麼

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

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

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

相信這裡有很多學習java的朋友,小編整理了一份java方面的學習資料,

有想要學習java的可以加一下我的學習群的喲,60833,4068,歡迎愛學習java的你們!

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例項。執行以上程式碼,在控制檯上輸出以下的結果:

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

歡迎關注胖胖程式設計師,視覺化學習java,每天更新文章,讓Java學習更加簡單。