4)public void remove():移除此線程局部變量當前線程的值。若是此線程局部變量隨後被當前線程讀取,且這期間當前線程沒有設置其值,則將調用其 initialValue() 方法從新初始化其值。這將致使在當前線程屢次調用 initialValue 方法。 html
下面是一個使用 ThreadLocal 的例子,每一個線程產生本身獨立的序列號。就是使用ThreadLocal存儲每一個線程獨立的序列號複本,線程之間互不干擾。package sync; public class SequenceNumber { // 定義匿名子類建立ThreadLocal的變量 private static ThreadLocal<Integer> seqNum = new ThreadLocal<Integer>() { // 覆蓋初始化方法 public Integer initialValue() { return 0; } }; // 下一個序列號 public int getNextNum() { seqNum.set(seqNum.get() + 1); return seqNum.get(); } private static class TestClient extends Thread { private SequenceNumber sn; public TestClient(SequenceNumber sn) { this.sn = sn; } // 線程產生序列號 public void run() { for (int i = 0; i < 3; i++) { System.out.println("thread[" + Thread.currentThread().getName() + "] sn[" + sn.getNextNum() + "]"); } } } /** * @param args */ public static void main(String[] args) { SequenceNumber sn = new SequenceNumber(); // 三個線程產生各自的序列號 TestClient t1 = new TestClient(sn); TestClient t2 = new TestClient(sn); TestClient t3 = new TestClient(sn); t1.start(); t2.start(); t3.start(); } }程序的運行結果以下:
thread[Thread-1] sn[1] thread[Thread-1] sn[2] thread[Thread-1] sn[3] thread[Thread-2] sn[1] thread[Thread-2] sn[2] thread[Thread-2] sn[3] thread[Thread-0] sn[1] thread[Thread-0] sn[2] thread[Thread-0] sn[3]
ThreadLocal和線程同步機制相比有什麼優點呢?ThreadLocal和線程同步機制都是爲了解決多線程中相同變量的訪問衝突問題。
在同步機制中,經過對象的鎖機制保證同一時間只有一個線程訪問變量。這時該變量是多個線程共享的,使用同步機制要求程序慎密地分析何時對變量進行讀寫,何時須要鎖定某個對象,何時釋放對象鎖等繁雜的問題,程序設計和編寫難度相對較大。 而 ThreadLocal 則從另外一個角度來解決多線程的併發訪問。ThreadLocal 會爲每個線程提供一個獨立的變量副本,從而隔離了多個線程對數據的訪問衝突。由於每個線程都擁有本身的變量副本,從而也就沒有必要對該變量進行同步了。ThreadLocal 提供了線程安全的共享對象,在編寫多線程代碼時,能夠把不安全的變量封裝進 ThreadLocal。
歸納起來講,對於多線程資源共享的問題,同步機制採用了「以時間換空間」的方式,而 ThreadLocal 採用了「以空間換時間」的方式。前者僅提供一份變量,讓不一樣的線程排隊訪問,然後者爲每個線程都提供了一份變量,所以能夠同時訪問而互不影響。
須要注意的是 ThreadLocal 對象是一個本質上存在風險的工具,應該在徹底理解將要使用的線程模型以後,再去使用 ThreadLocal 對象。這就引出了線程池(thread pooling)的問題,線程池是一種線程重用技術,有了線程池就沒必要爲每一個任務建立新的線程,一個線程可能會屢次使用,用於這種環境的任何 ThreadLocal 對象包含的都是最後使用該線程的代碼所設置的狀態,而不是在開始執行新線程時所具備的未被初始化的狀態。 那麼 ThreadLocal 是如何實現爲每一個線程保存獨立的變量的副本的呢?經過查看它的源代碼,咱們會發現,是經過把當前「線程對象」看成鍵,變量做爲值存儲在一個 Map 中。 java
private T setInitialValue() { T value = initialValue(); Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); return value; }
ThreadLocal不是用來解決對象共享訪問問題的,而主要是提供了保持對象的方法和避免參數傳遞的方便的對象訪問方式。概括了兩點:
一、每一個線程中都有一個本身的ThreadLocalMap類對象,能夠將線程本身的對象保持到其中,各管各的,線程能夠正確的訪問到本身的對象。
二、將一個共用的ThreadLocal靜態實例做爲key,將不一樣對象的引用保存到不一樣線程的ThreadLocalMap中,而後在線程執行的各處經過這個靜ThreadLocal實例的get()方法取得本身線程保存的那個對象,避免了將這個對象做爲參數傳遞的麻煩。 程序員
Synchronized仍是ThreadLocal? web
ThreadLocal以空間換取時間,提供了一種很是簡便的多線程實現方式。由於多個線程併發訪問無需進行等待,因此使用ThreadLocal 會得到更大的性能。雖然使用ThreadLocal會帶來更多的內存開銷,但這點開銷是微不足道的。由於保存在ThreadLocal中的對象,一般都是比較小的對象。另外使用ThreadLocal不能使用原子類型,只能使用Object類型。ThreadLocal的使用比synchronized要簡單得多。
ThreadLocal和Synchonized都用於解決多線程併發訪問。可是ThreadLocal與synchronized有本質的區別。synchronized是利用鎖的機制,使變量或代碼塊在某一時該只能被一個線程訪問。而ThreadLocal爲每個線程都提供了變量的副本,使得每一個線程在某一時間訪問到的並非同一個對象,這樣就隔離了多個線程對數據的數據共享。而Synchronized卻正好相反,它用於在多個線程間通訊時可以得到數據共享。
Synchronized用於線程間的數據共享,而ThreadLocal則用於線程間的數據隔離。
固然ThreadLocal並不能替代synchronized,它們處理不一樣的問題域。Synchronized用於實現同步機制,比ThreadLocal更加複雜。 安全
參考: 多線程
http://my.oschina.net/huangyong/blog/159725
http://my.oschina.net/huangyong/blog/159489
http://www.itokit.com/2012/0817/74676.html
http://www.java3z.com/cwbwebhome/article/article20/200026.html?id=4841 併發