最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java中ThreadLocal共享變量的使用

 更新時(shí)間:2024年01月02日 14:41:42   作者:EumenidesJ  
java.lang.ThreadLocal該類提供了線程局部變量,用于在當(dāng)前線程中共享數(shù)據(jù),本文主要介紹了Java中ThreadLocal共享變量的使用,具有一定的參考價(jià)值,感興趣的可以了解一下

一、ThreadLocal

我們知道多線程訪問同一個(gè)共享變量時(shí),會(huì)出現(xiàn)線程安全問題,為了保證線程安全開發(fā)者需要對(duì)共享變量的訪問操作進(jìn)行適當(dāng)?shù)耐讲僮?,如加鎖等同步操作。

除此之外,Java提供了ThreadLocal類,當(dāng)一個(gè)共享變量使用ThreadLocal聲明時(shí),它表明,當(dāng)每個(gè)線程訪問共享變量時(shí),會(huì)把共享變量復(fù)制一份到線程的工作內(nèi)存,之后線程對(duì)此共享變量進(jìn)行操作時(shí)操作的都是線程工作內(nèi)存的變量而不是主內(nèi)存中的共享變量,從而不需要加鎖的同步操作實(shí)現(xiàn)避免出現(xiàn)線程安全問題。

二、Thread使用代碼示例

public class ThreadLocalTest {
    private static ThreadLocal<String> variable = new ThreadLocal<>(); // (1) 
 
    public static void main(String[] args) throws InterruptedException {
        variable.set(Thread.currentThread().getName());  // (2)
        // 創(chuàng)建線程一
        var thread1 = new Thread(() -> {
            System.err.println("Thread Name before set: " + Thread.currentThread().getName() + " " + variable.get());  // (3)
            variable.set(Thread.currentThread().getName()); // (4)
            System.err.println("Thread Name after set: " + Thread.currentThread().getName() + " " + variable.get()); // (5)
        });


        var thread2 = new Thread(() -> {
            System.err.println("Thread Name before set: " + Thread.currentThread().getName() + " " + variable.get()); // (6)
            variable.set(Thread.currentThread().getName()); // (7)
            System.err.println("Thread Name after set: " + Thread.currentThread().getName() + " " + variable.get()); // (8)
        });
        thread1.start();  // (9)
        thread2.start(); // (10)
        Thread.sleep(2000); // (11)
        System.err.println("main thread: " + variable.get()); // (12)
    }
}

輸出:

Thread2 before set: Thread-1 null
Thread2 after set: Thread-1 Thread-1
Thread1 before set: Thread-0 null
Thread1 after set: Thread-0 Thread-0
main thread: main

示例中我們創(chuàng)建了兩個(gè)線程,每個(gè)線程里都讀取和設(shè)置全局的ThreadLcoal變量:

代碼(1)創(chuàng)建了一個(gè)ThreadLocal共享變量variable,這里其實(shí)設(shè)置的是主線程工作內(nèi)存里的共享變量副本

代碼(2)主線程設(shè)置ThreadLocal變量variable

代碼(3)線程一讀取共享變量variable的值

代碼(4)線程一設(shè)置共享變了variable的值,這里其實(shí)設(shè)置的是線程一工作內(nèi)存里的共享變量副本

代碼(5)線程一再次讀取共享變量variable的值

代碼(6)線程二讀取共享變量variable的值

代碼(7)線程二設(shè)置共享變了variable的值,這里其實(shí)設(shè)置的是線程二工作內(nèi)存里的共享變量副本

代碼(8)線程二再次讀取共享變量variable的值

代碼(9)啟動(dòng)線程一

代碼(10)啟動(dòng)線程二

代碼(11)主線程休眠2秒

代碼(12)主線程讀取共享變量variable的值

從輸出我們可以看到,每個(gè)兩個(gè)線程所操作的ThreadLocal變量互不影響,其實(shí)每個(gè)線程在設(shè)置和讀取共享變量variable時(shí)操作的都是共享變量在線程自己工作內(nèi)存里的副本,并不會(huì)影響到其他線程的值。

三、ThreadLocal原理

我們說線程操作ThreadLocal類型的變量時(shí),會(huì)復(fù)制一個(gè)變量副本到線程工作空間,然后所有操作都是對(duì)副本變量進(jìn)行的。那線程是怎么復(fù)制ThreadLocal變量到線程工作空間的,線程和ThreadLocal之前是怎么關(guān)聯(lián)的。首先我們來看一看Thread的結(jié)構(gòu)

Thread

可以看到Thread類有很多屬性,我們現(xiàn)在只關(guān)心threadLocalsinheritableThreadLocals,這兩個(gè)變量都是ThreadLocalMap類型的實(shí)例。TThreadLocalMap是一個(gè)ThreadLocal.ThreadLocalMap類型,這是一個(gè)特殊的Map。

首先看一下在前面的例子中我們是怎么在線程中使用ThreadLocal變量的,

variable.set(Thread.currentThread().getName()); // 設(shè)置ThreadLocal變量
variable.get();    // 讀取ThreadLocal變量

接下來我們看看ThreadLocal變量的set和get方法。

ThreadLocal.get()相關(guān)源碼如下:

public T get() {
  return get(Thread.currentThread()); // (1)
}

private T get(Thread t) {
  ThreadLocalMap map = getMap(t);  // (2)
  if (map != null) {
    ThreadLocalMap.Entry e = map.getEntry(this); // (3)
    if (e != null) {
      @SuppressWarnings("unchecked")
      T result = (T) e.value;
      return result;
    }
  }
  return setInitialValue(t);   // (4)
}

ThreadLocalMap getMap(Thread t) {
  return t.threadLocals;    // (5)
}

從代碼(1)可以看到,調(diào)用ThreadLocal的get()方法時(shí),會(huì)將當(dāng)前線程作為參數(shù)傳遞。代碼(2)調(diào)用getMap方法獲取ThreadLocalMap類型變量,如果map不為空則把ThreadLocal實(shí)例作為key獲取值,這個(gè)值就是ThreadLocal變量的值(5)可以看到getMap方法返回的就是Thread類型的threadLocals變量。根據(jù)上述分析我們可以知道:

線程在讀取ThreadLocal變量時(shí),實(shí)際是獲取當(dāng)前線程的threadLocals變量,然后把ThreadLocal實(shí)例當(dāng)做key從threadLocals查詢對(duì)應(yīng)的值。也就是說線程讀取的ThreadLocal的實(shí)際值并不是存在ThreadLocal實(shí)例里的,而是存在線程的threadLocals里面,threadLocals是一個(gè)ThreadLocal.ThreadLocalMap,這是一個(gè)特殊的Map,key為ThreadLocal實(shí)例,值為ThreadLocal變量的實(shí)際值。ThreadLoca相當(dāng)于一個(gè)轉(zhuǎn)接口,連接Thread和ThreadLocal。

代碼(4)可以看到如果當(dāng)前線程的threadLocals變量為null,會(huì)調(diào)用ThreadLocal的setInitialValue方法初始化當(dāng)前線程的threadLocals實(shí)例。

private T setInitialValue(Thread t) {
  T value = initialValue();
  ThreadLocalMap map = getMap(t);
  if (map != null) {
    map.set(this, value);
  } else {
    createMap(t, value);
  }
  if (this instanceof TerminatingThreadLocal<?> ttl) {
    TerminatingThreadLocal.register(ttl);
  }
  if (TRACE_VTHREAD_LOCALS) {
    dumpStackIfVirtualThread();
  }
  return value;
}

void createMap(Thread t, T firstValue) {
  t.threadLocals = new ThreadLocalMap(this, firstValue); // (1)
}

setInitialValue方法會(huì)創(chuàng)建參數(shù)傳遞線程的threadLocals值,并且設(shè)置一個(gè)初始化值。從代碼(1)可以看到threadLocals的key為ThreadLocal實(shí)例。

下面再看看ThreadLocal的set方法:

public void set(T value) {
  set(Thread.currentThread(), value);   // (1)
  if (TRACE_VTHREAD_LOCALS) {
    dumpStackIfVirtualThread();
  }
}

private void set(Thread t, T value) {
  ThreadLocalMap map = getMap(t);
  if (map != null) {
    map.set(this, value);
  } else {
    createMap(t, value);
  }
}

從代碼(1)可以看到,調(diào)用ThreadLocald的set方法會(huì)向當(dāng)前線程的threadLocals變量里設(shè)置傳遞的值value,key為ThreadLocal實(shí)例的引用,和get方法一樣,如果當(dāng)前線程的threadLocals變量為null,則會(huì)創(chuàng)建一個(gè)ThreadLocalMap變量并把value設(shè)置為初始值。

總結(jié):在每個(gè)線程內(nèi)部都有一個(gè)threadLocals變量,該變量類型為ThreadLocal.ThreadLocalMap,其中key為我們定義的ThreadLocal變量的this引用,value則為我們使用set方法設(shè)置的值。每個(gè)線程的本地變量存放在線程自己的內(nèi)存變量threadLocals中。

如果線程不銷毀,那么對(duì)應(yīng)的本地變量就會(huì)一直存在,所以可能存在內(nèi)存溢出,因此使用完畢之后要記得調(diào)用ThreadLocal的remove方法刪除對(duì)應(yīng)線程的threadLocals變量里的值。

注意:ThreadLocal不具備繼承性,也就是說子線程并不能訪問父線程的ThreadLocal變量。

到此這篇關(guān)于Java中ThreadLocal共享變量的使用的文章就介紹到這了,更多相關(guān)Java ThreadLocal共享變量內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java連接Redis報(bào)錯(cuò):NoSuchElementException: Unable to validate object的解決辦法

    Java連接Redis報(bào)錯(cuò):NoSuchElementException: Unable to&nb

    這篇文章主要介紹了Java連接Redis報(bào)錯(cuò):NoSuchElementException: Unable to validate object的解決辦法,文中通過圖文講解的非常詳細(xì),具有一定的參考價(jià)值,需要的朋友可以參考下
    2024-12-12
  • 詳解Spring如何避免被JVM 垃圾回收

    詳解Spring如何避免被JVM 垃圾回收

    如果Spring 被回收掉,Spring管理的bean全部會(huì)被回收,那我們的Java應(yīng)用不就被一鍋端了嗎?所以本文小編將和大家一起聊聊Spring如何避免被JVM垃圾回收,需要的朋友可以參考下
    2023-11-11
  • Java通過動(dòng)態(tài)規(guī)劃設(shè)計(jì)股票買賣最佳時(shí)機(jī)

    Java通過動(dòng)態(tài)規(guī)劃設(shè)計(jì)股票買賣最佳時(shí)機(jī)

    動(dòng)態(tài)規(guī)劃可謂是大名鼎鼎,筆試面試中的高頻考點(diǎn),也是重點(diǎn)難點(diǎn),動(dòng)態(tài)規(guī)劃類型題目靈活多變,難度系數(shù)也相對(duì)較高,往往我們做不好動(dòng)態(tài)規(guī)劃的題目就會(huì)與心儀的offer失之交臂,本篇文章我們就一起來研究一下動(dòng)態(tài)規(guī)劃設(shè)計(jì)股票買賣最佳時(shí)機(jī)
    2022-10-10
  • Java?SWT中常見彈出框?qū)嵗偨Y(jié)

    Java?SWT中常見彈出框?qū)嵗偨Y(jié)

    剛開始寫Java工具的小伙伴可能不知道怎么寫消息對(duì)話框,在這里總結(jié)一些常用的幾種消息彈出框,下面這篇文章主要給大家介紹了關(guān)于Java?SWT中常見彈出框的相關(guān)資料,需要的朋友可以參考下
    2023-01-01
  • 淺談Java到底是值傳遞還是引用傳遞呢

    淺談Java到底是值傳遞還是引用傳遞呢

    今天帶大家學(xué)習(xí)Java的相關(guān)知識(shí),文章圍繞著Java到底是值傳遞還是引用傳遞展開,文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下
    2021-06-06
  • Java中的StopWatch計(jì)時(shí)利器使用指南

    Java中的StopWatch計(jì)時(shí)利器使用指南

    StopWatch通常用于測(cè)量一段代碼執(zhí)行所花費(fèi)的時(shí)間,它能夠精確地記錄開始時(shí)間、結(jié)束時(shí)間,并計(jì)算出這中間的時(shí)間差,下面給大家介紹Java中的StopWatch計(jì)時(shí)利器的深度解析與使用指南,感興趣的朋友一起看看吧
    2025-05-05
  • Java中實(shí)現(xiàn)Comparator接口和用法實(shí)例(簡(jiǎn)明易懂)

    Java中實(shí)現(xiàn)Comparator接口和用法實(shí)例(簡(jiǎn)明易懂)

    這篇文章主要介紹了Java中實(shí)現(xiàn)Comparator接口和用法實(shí)例(簡(jiǎn)明易懂),本文給出實(shí)現(xiàn)Comparator接口的實(shí)例和使用這個(gè)接口的代碼實(shí)例,需要的朋友可以參考下
    2015-05-05
  • JAVA“無法驗(yàn)證證書。將不執(zhí)行該應(yīng)用程序。”提示解決辦法

    JAVA“無法驗(yàn)證證書。將不執(zhí)行該應(yīng)用程序?!碧崾窘鉀Q辦法

    這篇文章主要給大家介紹了關(guān)于JAVA“無法驗(yàn)證證書,將不執(zhí)行該應(yīng)用程序”提示的解決辦法,要解決Java無法驗(yàn)證證書的問題,可以嘗試下本文的方法,需要的朋友可以參考下
    2024-03-03
  • Spring MVC中使用Google kaptcha驗(yàn)證碼的方法詳解

    Spring MVC中使用Google kaptcha驗(yàn)證碼的方法詳解

    kaptcha 是一個(gè)非常實(shí)用的驗(yàn)證碼生成工具。有了它,你可以生成各種樣式的驗(yàn)證碼,因?yàn)樗强膳渲玫?,下面這篇文章主要給大家介紹了關(guān)于Spring MVC中使用Google kaptcha驗(yàn)證碼的方法,需要的朋友可以參考借鑒,下面來一起看看吧。
    2017-10-10
  • 解決IDEA 啟動(dòng)Tomcat控制臺(tái)亂碼問題

    解決IDEA 啟動(dòng)Tomcat控制臺(tái)亂碼問題

    今天在Idea中用Tomcat跑一個(gè)Web項(xiàng)目,啟動(dòng)后,Tomcat日志在控制臺(tái)打印出來都是亂碼,初次遇到這個(gè)問題真的很棘手,今天小編帶領(lǐng)大家一起看看解決方法
    2018-07-07

最新評(píng)論

洛隆县| 呼玛县| 吴川市| 桑植县| 晋江市| 洛南县| 庆城县| 资阳市| 正镶白旗| 康定县| 丹阳市| 辽源市| 铜鼓县| 长岛县| 华亭县| 天峨县| 徐州市| 玉树县| 东丰县| 辛集市| 林芝县| 青浦区| 宁晋县| 桐乡市| 武安市| 赤峰市| 安康市| 关岭| 铜陵市| 甘肃省| 科技| 务川| 泾源县| 左云县| 胶南市| 博乐市| 温泉县| 天水市| 视频| 临高县| 汶上县|