ThreadLocal是如何解決多線程的

ThreadLocal爲解決多線程程序的併發問題提供了一種新的思路。當使用ThreadLocal維護變量時,ThreadLocal爲每一個變量的線程提供獨立的變量副本,因此每個線程均可以獨立地改變本身的副本,而不會影響其它線程所對應的副本。安全

ThreadLocal類接口很簡單,只有4個方法,咱們先來了解一下:多線程

•void set(Object value)設置當前線程的線程局部變量的值。併發

•public Object get()該方法返回當前線程所對應的線程局部變量。this

•public void remove()將當前線程局部變量的值刪除,目的是爲了減小內存的佔用,該方法是JDK 5.0新增的方法。須要指出的是,當線程結束後,對應該線程的局部變量將自動被垃圾回收,因此顯式調用該方法清除線程的局部變量並非必須的操做,但它能夠加快內存回收的速度。spa

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

ThreadLocal是如何作到爲每個線程維護變量的副本的呢?其實實現的思路很簡單:在ThreadLocal類中有一個Map,用於存儲每個線程的變量副本,Map中元素的鍵爲線程對象,而值對應線程的變量副本。咱們本身就能夠提供一個簡單的實現版本:設計

package com.wxp.learn;
public class Test02 {
    //經過匿名內部類覆蓋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)throws Exception {
        // TODO Auto-generated method stub
      Test02 sn =  new Test02();
      //3個線程共享sn,各自產生序列號
      TestClient t1 = new TestClient(sn);
      TestClient t2 = new TestClient(sn);
      TestClient t3 = new TestClient(sn);
      t1.start();t2.start();t3.start();
      //阻塞,使main不退出
      System.in.read();
      }
      private static class TestClient extends Thread{
          private Test02 sn;對象

        public TestClient(Test02 sn) {
            super();
            this.sn = sn;
        }
         public void run(){
             
             for (int i = 0; i <3; i++) {
                //每一個線程打印出3個序列值
                 System.out.println("thread["+Thread.currentThread().getName()
                         +"]-->sn["+sn.getNextNum()+"]");
            }
         }
      }
}接口

執行輸出內容:內存

thread[Thread-2]-->sn[1]
thread[Thread-0]-->sn[1]
thread[Thread-1]-->sn[1]
thread[Thread-0]-->sn[2]
thread[Thread-2]-->sn[2]
thread[Thread-0]-->sn[3]
thread[Thread-1]-->sn[2]
thread[Thread-2]-->sn[3]
thread[Thread-1]-->sn[3]

由此咱們會發現每一個線程所產生的序號雖然都共享同一個Test02實例,但它們並無發生相互干擾的狀況,而是各自產生獨立的序列號,這是由於咱們經過ThreadLocal爲每個線程提供了單獨的副本。

Thread同步機制的比較

ThreadLocal和線程同步機制相比有什麼優點呢?ThreadLocal和線程同步機制都是爲了解決多線程中相同變量的訪問衝突問題。

在同步機制中,經過對象的鎖機制保證同一時間只有一個線程訪問變量。這時該變量是多個線程共享的,使用同步機制要求程序慎密地分析何時對變量進行讀寫,何時須要鎖定某個對象,何時釋放對象鎖等繁雜的問題,程序設計和編寫難度相對較大。

而ThreadLocal則從另外一個角度來解決多線程的併發訪問。ThreadLocal會爲每個線程提供一個獨立的變量副本,從而隔離了多個線程對數據的訪問衝突。由於每個線程都擁有本身的變量副本,從而也就沒有必要對該變量進行同步了。ThreadLocal提供了線程安全的共享對象,在編寫多線程代碼時,能夠把不安全的變量封裝進ThreadLocal。

相關文章
相關標籤/搜索