ThreadLocal

ThreadLocal 直譯為 “線程本地,但如果真那么認(rèn)為就是錯的,ThreadLocal 它是一個容器,用來存放線程的局部變量.ThreadLocal的誕生 是為了解決多線程并發(fā)問題而設(shè)計的,只不過設(shè)計比較難用而已,至今沒有得到廣泛應(yīng)用而已。

 一個序列號生成器的程序可能同時會有多個線程并發(fā)訪問它,要保證每個序列號都是自增的,并且互不干擾。

 直接上代碼:

先定義了一個接口:

    public interface Sequence {


    int getNumber();
}

序列號自增

public class ClientThread extends Thread {

    private Sequence sequence;

    public ClientThread(Sequence sequence) {
        this.sequence = sequence;
    }

    @Override
    public void run() {
//        super.run();

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

            System.out.println(Thread.currentThread().getName()+"=>"+sequence.getNumber());
        }

    }
}

此時這里先不用ThreadLocal 來實現(xiàn)

public class SequenceA implements  Sequence {


     private static  int number = 0;

    @Override
    public int getNumber() {

        number = number + 1;
        return number;
    }


    public static void main(String[] args) {

        Sequence sequence = new SequenceA();

        ClientThread thread1 = new ClientThread(sequence);

        ClientThread thread2 = new ClientThread(sequence);

        ClientThread thread3  = new ClientThread(sequence);

        thread1.start();
        thread2.start();
        thread3.start();


    }
}

看一下運行的結(jié)果圖:


這里寫圖片描述

為什么會出現(xiàn)這種效果? 序列號是連續(xù)自增的,共享的static 變量無法保證線程安全,才會出現(xiàn)這種情況的。所以我們要做到線程安全的。

public class SequenceB  implements  Sequence{

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

        @Override
        protected Integer initialValue() {   // 思考 此時為什么是protected?
            return 0;
        }
    };


    @Override
    public int getNumber() {

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

        return numberContainer.get();
    }

    public static void main(String[] args) {

        Sequence sequence = new SequenceB();

        ClientThread thread1 = new ClientThread(sequence);

        ClientThread thread2 = new ClientThread(sequence);

        ClientThread thread3 = new ClientThread(sequence);

        thread1.start();
        thread2.start();
        thread3.start();


    }

}

再來看看運行的結(jié)果:


這里寫圖片描述

此時每個線程都是安全的,每個線程的數(shù)字都是1-3遞增.ThreadLocal 保證了每個線程都是相互獨立的,同樣是static 變量,對于不同的線程,它沒有被共享,而是各個線程各一份,這樣就保證了線程的安全。

這里寫圖片描述

這是ThreadLocal 的api

當(dāng)然我們也可以自己來實現(xiàn)一個ThreadLocal

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by hello world on 2017/8/8.
 */
public class MyThreadLocal<T> {

       private Map<Thread,T> container = Collections.synchronizedMap(new HashMap<Thread, T>()); // 此時 container 是線程安全的map 這是為什么?


    // set 方法實現(xiàn)
      public void Set(T value){

          container.put(Thread.currentThread(),value);
      }

    //
    public T get(){

        Thread thread = Thread.currentThread();

        T value = container.get(thread);

        if(value ==null &&!container.containsKey(thread)){
            value = initialValue();
            container.put(thread,value);
        }

         return  value;
    }


    public void remove(){
        container.remove(Thread.currentThread());
    }


    protected  T initialValue(){

        return  null;
    }




}

我們再來用MyThreadLocal 來實現(xiàn)一編

 public class SequenceC implements  Sequence {

     private  static  MyThreadLocal<Integer> numberContainer = new MyThreadLocal<Integer>(){
         @Override
         protected Integer initialValue() {

             return 0;
         }
     };


    @Override
    public int getNumber() {
        numberContainer.Set(numberContainer.get()+1);
        return  numberContainer.get();
    }

    public static void main(String[] args) {
          Sequence sequence = new SequenceB();

        ClientThread thread1 = new ClientThread(sequence);

        ClientThread thread2 = new ClientThread(sequence);

        ClientThread thread3 = new ClientThread(sequence);

        thread1.start();
        thread2.start();
        thread3.start();

    }

}

效果都是一樣,就不截圖了。當(dāng)我們遇到static 修飾的變量,多個線程需要獨享自己static成員變量?
如果需要,可以考慮用ThreadLocal .

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容