第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

ThreadLocal 的使用

1. 前言

本節(jié)內(nèi)容主要是對 ThreadLocal 進行深入的講解,具體內(nèi)容點如下:

  • 了解 ThreadLocal 的誕生,以及總體概括,是學(xué)習(xí)本節(jié)知識的基礎(chǔ);
  • 了解 ThreadLocal 的作用,從整體層面理解 ThreadLocal 的程序作用,為本節(jié)的次重點;
  • 掌握 ThreadLocal set 方法的使用,為本節(jié)重點內(nèi)容;
  • 掌握 ThreadLocal get 方法的使用,為本節(jié)重點內(nèi)容;
  • 掌握 ThreadLocal remove 方法的使用,為本節(jié)重點內(nèi)容;
  • 掌握多線程下的 ThreadLocal 的使用,為本節(jié)內(nèi)容的核心。

2. ThreadLocal 概述

誕生:早在 JDK 1.2 的版本中就提供 java.lang.ThreadLocal,ThreadLocal 為解決多線程程序的并發(fā)問題提供了一種新的思路。使用這個工具類可以很簡潔地編寫出優(yōu)美的多線程程序。

概述:ThreadLocal 很容易讓人望文生義,想當(dāng)然地認(rèn)為是一個 “本地線程”。其實,ThreadLocal 并不是一個 Thread,而是 Thread 的局部變量,也許把它命名為 ThreadLocalVariable 更容易讓人理解一些。

當(dāng)使用 ThreadLocal 維護變量時,ThreadLocal 為每個使用該變量的線程提供獨立的變量副本,所以每一個線程都可以獨立地改變自己的副本,而不會影響其它線程所對應(yīng)的副本。

總體概括:從線程的角度看,目標(biāo)變量就象是線程的本地變量,這也是類名中 “Local” 所要表達的意思。

了解完 ThreadLocal 的總體介紹后,對其有了一個總體的了解,那我們接下來繼續(xù)探究 ThreadLocal 的真實面貌以及使用。

3. ThreadLocal 的作用

作用:ThreadLocal 是 JDK 包提供的,它提供了線程本地變量,也就是如果你創(chuàng)建了一個 ThreadLocal 變量,那么訪問這個變量的每個線程都會有這個變量的一個本地副本。當(dāng)多個線程操作這個變量時,實際操作的是自己本地內(nèi)存里面的變量,從而避免了線程安全問題。

圖片描述

ThreadLocal 是線程本地存儲,在每個線程中都創(chuàng)建了一個 ThreadLocalMap 對象,每個線程可以訪問自己內(nèi)部 ThreadLocalMap 對象內(nèi)的 value。通過這種方式,避免資源在多線程間共享。

使用場景:如為每個線程分配一個 JDBC 連接 Connection。這樣就可以保證每個線程的都在各自的 Connection 上進行數(shù)據(jù)庫的操作,不會出現(xiàn) A 線程關(guān)了 B 線程正在使用的 Connection。還有 Session 管理等問題。

4. ThreadLocal set 方法

方法介紹:set 方法是為了設(shè)置 ThreadLocal 變量,設(shè)置成功后,該變量只能夠被當(dāng)前線程訪問,其他線程不可直接訪問操作改變量。

實例

public class DemoTest{
    public static void main(String[] args){
        ThreadLocal<String> localVariable = new ThreadLocal<> () ;
        localVariable.set("Hello World");
    }
}

Tips:set 方法可以設(shè)置任何類型的值,無論是 String 類型 ,Integer 類型,Object 等類型,原因在于 set 方法的 JDK 源碼實現(xiàn)是基于泛型的實現(xiàn),此處只是拿 String 類型進行的舉例。

實例

public void set(T value) { // T value , 泛型實現(xiàn),可以 set 任何對象類型
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

5. ThreadLocal get 方法

方法介紹:get 方法是為了獲取 ThreadLocal 變量的值,get 方法沒有任何入?yún)?,直接調(diào)用即可獲取。

實例

public class DemoTest{
    public static void main(String[] args){
        ThreadLocal<String> localVariable = new ThreadLocal<> () ;
        localVariable.set("Hello World");
        System.out.println(localVariable.get());
    }
}

結(jié)果驗證

Hello World

探究:請看如下程序,并給出輸出結(jié)果

實例

public class DemoTest{
    public static void main(String[] args){
        ThreadLocal<String> localVariable = new ThreadLocal<> () ;
        localVariable.set("Hello World");
        localVariable.set("World is beautiful");
        System.out.println(localVariable.get());
        System.out.println(localVariable.get());
    }
}

探究解析:從程序中來看,我們進行了兩次 set 方法的使用。

第一次 set 的值為 Hello World ;第二次 set 的值為 World is beautiful。接下來我們進行了兩次打印輸出 get 方法,那么這兩次打印輸出的結(jié)果都會是 World is beautiful。 原因在于第二次 set 的值覆蓋了第一次 set 的值,所以只能 get 到 World is beautiful。

結(jié)果驗證

World is beautiful
World is beautiful

總結(jié):ThreadLocal 中只能設(shè)置一個變量值,因為多次 set 變量的值會覆蓋前一次 set 的值,我們之前提出過,ThreadLocal 其實是使用 ThreadLocalMap 進行的 value 存儲,那么多次設(shè)置會覆蓋之前的 value,這是 get 方法無需入?yún)⒌脑?,因為只有一個變量值。

6. ThreadLocal remove 方法

方法介紹:remove 方法是為了清除 ThreadLocal 變量,清除成功后,該 ThreadLocal 中沒有變量值。

實例

public class DemoTest{
    public static void main(String[] args){
        ThreadLocal<String> localVariable = new ThreadLocal<> () ;
        localVariable.set("Hello World");
        System.out.println(localVariable.get());
        localVariable.remove();
        System.out.println(localVariable.get());
    }
}

Tips:remove 方法同 get 方法一樣,是沒有任何入?yún)⒌?,因?ThreadLocal 中只能存儲一個變量值,那么 remove 方法會直接清除這個變量值。

結(jié)果驗證

Hello World
null

7. 多線程下的 ThreadLocal

對 ThreadLocal 的常用方法我們已經(jīng)進行了詳細的講解,那么多線程下的 ThreadLocal 才是它存在的真實意義,那么問了更好的學(xué)習(xí)多線程下的 ThreadLocal,我們來進行場景的創(chuàng)建,通過場景進行代碼實驗,更好的體會并掌握 ThreadLocal 的使用。

場景設(shè)計

  • 創(chuàng)建一個全局的靜態(tài) ThreadLocal 變量,存儲 String 類型變量;
  • 創(chuàng)建兩個線程,分別為 threadOne 和 threadTwo;
  • threadOne 進行 set 方法設(shè)置,設(shè)置完成后沉睡 5000 毫秒,蘇醒后進行 get 方法打印;
  • threadTwo 進行 set 方法設(shè)置,設(shè)置完成后直接 get 方法打印,打印完成后調(diào)用 remove 方法,并打印 remove 方法調(diào)用完畢語句;
  • 開啟線程 threadOne 和 threadTwo ;
  • 執(zhí)行程序,并觀察打印結(jié)果。

結(jié)果預(yù)期:在 threadOne 設(shè)置成功后進入了 5000 毫秒的休眠狀態(tài),此時由于只有 threadTwo 調(diào)用了 remove 方法,不會影響 threadOne 的 get 方法打印,這體現(xiàn)了 ThreadLocal 變量的最顯著特性,線程私有操作。

實例

public class DemoTest{
    static ThreadLocal<String> local = new ThreadLocal<>();
    public static void main(String[] args){

        Thread threadOne = new Thread(new Runnable() {
            @Override
            public void run() {
                local.set("threadOne's local value");
                try {
                    Thread.sleep(5000); //沉睡5000 毫秒,確保 threadTwo 執(zhí)行 remove 完成
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(local.get());
            }
        });
        Thread threadTwo = new Thread(new Runnable() {
            @Override
            public void run() {
                local.set("threadTwo's local value");
                System.out.println(local.get());
                local.remove();
                System.out.println("local 變量執(zhí)行 remove 操作完畢。");
            }
        });
        threadTwo. start();
        threadOne. start();
    }
}

結(jié)果驗證

threadTwo's local value
local 變量執(zhí)行 remove 操作完畢。
threadOne's local value

從以上結(jié)果來看,在 threadTwo 執(zhí)行完 remove 方法后,threadOne 仍然能夠成功打印,這更加證明了 ThreadLocal 的專屬特性,線程獨有數(shù)據(jù),其他線程不可侵犯。

8. 小結(jié)

ThreadLocal 是解決線程安全問題一個很好的思路,它通過為每個線程提供一個獨立的變量副本解決了變量并發(fā)訪問的沖突問題。在很多情況下,ThreadLocal 比直接使用 synchronized 同步機制解決線程安全問題更簡單,更方便,且結(jié)果程序擁有更高的并發(fā)性。

本節(jié)的重中之重是掌握 ThreadLocal 的方法使用以及其特點,核心內(nèi)容為多線程下的 ThreadLocal 的使用。