日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

浅谈ThreadLocal

發布時間:2024/1/1 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 浅谈ThreadLocal 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1. ThreadLocal簡介

ThreadLocal叫做線程變量,意思是ThreadLocal中填充的變量屬于當前線程,該變量對其他線程而言是隔離的,也就是說該變量是當前線程獨有的變量。ThreadLocal為變量在每個線程中都創建了一個副本,那么每個線程可以訪問自己內部的副本變量。

ThreadLoal 變量,線程局部變量,同一個 ThreadLocal 所包含的對象,在不同的 Thread 中有不同的副本。這里有幾點需要注意:

  • 因為每個 Thread 內有自己的實例副本,且該副本只能由當前 Thread 使用。這是也是 ThreadLocal 命名的由來。
  • 既然每個 Thread 有自己的實例副本,且其它 Thread 不可訪問,那就不存在多線程間共享的問題。

ThreadLocal 提供了線程本地的實例。它與普通變量的區別在于,每個使用該變量的線程都會初始化一個完全獨立的實例副本。ThreadLocal 變量通常被private static修飾。當一個線程結束時,它所使用的所有 ThreadLocal 相對的實例副本都可被回收。

總的來說,ThreadLocal 適用于每個線程需要自己獨立的實例且該實例需要在多個方法中被使用,也即變量在線程間隔離而在方法或類間共享的場景。

2. ThreadLocal與Synchronized的區別

ThreadLocal其實是與線程綁定的一個變量。ThreadLocal和Synchonized都用于解決多線程并發訪問。

但是ThreadLocal與synchronized有本質的區別:

  • Synchronized用于線程間的數據共享,而ThreadLocal則用于線程間的數據隔離。

  • Synchronized是利用鎖的機制,使變量或代碼塊在某一時該只能被一個線程訪問。而ThreadLocal為每一個線程都提供了變量的副本

  • ,使得每個線程在某一時間訪問到的并不是同一個對象,這樣就隔離了多個線程對數據的數據共享。而Synchronized卻正好相反,它用于在多個線程間通信時能夠獲得數據共享。

    一句話理解ThreadLocal,向ThreadLocal里面存東西就是向它里面的Map存東西的,然后ThreadLocal把這個Map掛到當前的線程底下,這樣Map就只屬于這個線程了。

    3. 兩大使用場景

    3.1 典型場景1:

    每個線程需要一個獨享的對象(通常是工具類,典型需要使用的類有 SimpleDate Format和 Random)

    public class ThreadLocalNormalUsage00 {private static ExecutorService threadPool = Executors.newFixedThreadPool(10);public static void main(String[] args) throws InterruptedException {for (int j = 0; j < 1000; j++) {int i = j;threadPool.execute(() -> System.out.println(date(i)));Thread.sleep(100L);}threadPool.shutdown();}public static String date(int seconds) {return ThreadSafeFormatter.dateFormatThreadLocal.get().format(new Date(seconds * 1000L));} } class ThreadSafeFormatter {public static ThreadLocal<SimpleDateFormat> dateFormatThreadLocal= ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd hh:mm:ss")); }

    3.2 典型場景2:

    每個線程內需要保存全局變量(例如在攔截器中獲取用戶信息),可以讓不同方法直接使用,避免參數傳遞的麻煩。例如用 Threadlocal保存一些業務內容(用戶權限信息、從用戶系統取到的用戶名、 user id等),這些信息在同一個線程內相同,但是不同的線程使用的業務內容是不相同的。

    package com.zeny.threadstudy.threadpool;public class ThreadLocalNormalUsage06 {public static void main(String[] args) {new Service1().process();} } class Service1 {public void process() {User user = new User("超哥");UserContextHolder.holder.set(user);new Service2().process();} } class Service2 {public void process() {User user = UserContextHolder.holder.get();System.out.println("Service2 get user message: " + user);new Service3().process();} } class Service3 {public void process() {User user = UserContextHolder.holder.get();System.out.println("Service3 get user message: " + user);UserContextHolder.holder.remove();} } class UserContextHolder {public static ThreadLocal<User> holder = new ThreadLocal<>(); } class User {String name;public User(String name) {this.name = name;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +'}';} }

    4.Threadlocal的兩個作用

    1.讓某個需要用到的對象在線程間隔離(每個線程都有自己的獨立的對象)

    2.在任何方法中都可以輕松獲取到該對象

    5.ThreadLocal原理

    5.1 ThreadLocal的set()方法

    public void set(T value) {//1、獲取當前線程Thread t = Thread.currentThread();//2、獲取線程中的屬性 threadLocalMap ,如果threadLocalMap 不為空,//則直接更新要保存的變量值,否則創建threadLocalMap,并賦值ThreadLocalMap map = getMap(t);if (map != null)map.set(this, value);else// 初始化thradLocalMap 并賦值createMap(t, value);}

    從上面的代碼可以看出,ThreadLocal 在set賦值的時候首先會獲取當前線程thread,并獲取thread線程中的ThreadLocalMap屬性。如果map屬性不為空,則直接更新value值,如果map為空,則實例化threadLocalMap,并將value值初始化。那么ThreadLocalMap又是什么呢,還有createMap又是怎么做的,我們繼續往下看。大家最后自己再idea上跟下源碼,會有更深的認識。
    static class ThreadLocalMap {

    static class ThreadLocalMap {/*** The entries in this hash map extend WeakReference, using* its main ref field as the key (which is always a* ThreadLocal object). Note that null keys (i.e. entry.get()* == null) mean that the key is no longer referenced, so the* entry can be expunged from table. Such entries are referred to* as "stale entries" in the code that follows.*/static class Entry extends WeakReference<ThreadLocal<?>> {/** The value associated with this ThreadLocal. */Object value;Entry(ThreadLocal<?> k, Object v) {super(k);value = v;}}}

    可看出ThreadLocalMap是ThreadLocal的內部靜態類,而它的構成主要是用Entry來保存數據 ,而且還是繼承的弱引用。在Entry內部使用ThreadLocal作為key,使用我們設置的value作為value。

    //這個是threadlocal 的內部方法 void createMap(Thread t, T firstValue) {t.threadLocals = new ThreadLocalMap(this, firstValue);}//ThreadLocalMap 構造方法 ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {table = new Entry[INITIAL_CAPACITY];int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);table[i] = new Entry(firstKey, firstValue);size = 1;setThreshold(INITIAL_CAPACITY);}

    5.2 ThreadLocal的get方法

    public T get() {//1、獲取當前線程Thread t = Thread.currentThread();//2、獲取當前線程的ThreadLocalMapThreadLocalMap map = getMap(t);//3、如果map數據為空,if (map != null) {//3.1、獲取threalLocalMap中存儲的值ThreadLocalMap.Entry e = map.getEntry(this);if (e != null) {@SuppressWarnings("unchecked")T result = (T)e.value;return result;}}//如果是數據為null,則初始化,初始化的結果,TheralLocalMap中存放key值為threadLocal,值為nullreturn setInitialValue();}private T setInitialValue() {T value = initialValue();Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null)map.set(this, value);elsecreateMap(t, value);return value;}

    5.3 ThreadLocal的remove()方法

    public void remove() {ThreadLocalMap m = getMap(Thread.currentThread());if (m != null)m.remove(this);}

    remove方法,直接將ThrealLocal 對應的值從當前相差Thread中的ThreadLocalMap中刪除。為什么要刪除,這涉及到內存泄露的問題。實際上 ThreadLocalMap 中使用的 key 為 ThreadLocal 的弱引用,弱引用的特點是,如果這個對象只存在弱引用,那么在下一次垃圾回收的時候必然會被清理掉。所以如果 ThreadLocal 沒有被外部強引用的情況下,在垃圾回收的時候會被清理掉的,這樣一來 ThreadLocalMap中使用這個 ThreadLocal 的 key 也會被清理掉。但是,value 是強引用,不會被清理,這樣一來就會出現 key 為 null 的 value。ThreadLocal其實是與線程綁定的一個變量,如此就會出現一個問題:如果沒有將ThreadLocal內的變量刪除(remove)或替換,它的生命周期將會與線程共存。通常線程池中對線程管理都是采用線程復用的方法,在線程池中線程很難結束甚至于永遠不會結束,這將意味著線程持續的時間將不可預測,甚至與JVM的生命周期一致。舉個例字,如果ThreadLocal中直接或間接包裝了集合類或復雜對象,每次在同一個ThreadLocal中取出對象后,再對內容做操作,那么內部的集合類和復雜對象所占用的空間可能會開始持續膨脹。

    5.4 ThreadLocal與Thread,ThreadLocalMap之間的關系

    Thread、THreadLocal、ThreadLocalMap之間啊的數據關系圖

    從這個圖中我們可以非常直觀的看出,ThreadLocalMap其實是Thread線程的一個屬性值,而ThreadLocal是維護ThreadLocalMap

    這個屬性指的一個工具類。Thread線程可以擁有多個ThreadLocal維護的自己線程獨享的共享變量(這個共享變量只是針對自己線程里面共享)

    6.ThreadLocal出現空指針問題

    如下代碼,當執行get方法的時候,會獲取null,然后進行拆箱操作,因為對象為空,所以報空指針異常。

    package com.zeny.threadstudy.threadpool;public class Main {private static ThreadLocal<Integer> threadLocal = new ThreadLocal<>();public int getValue() {return threadLocal.get();}public void setValue(int value) {threadLocal.set(value);}public static void main(String[] args) {Main main = new Main();main.getValue(); //會出現空指針異常main.setValue(10);main.getValue();} }

    原文鏈接:https://blog.csdn.net/u010445301/article/details/111322569

    總結

    以上是生活随笔為你收集整理的浅谈ThreadLocal的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: av av在线| 国产在线高清 | 亚洲4438| 成人免费毛片男人用品 | 国产日韩欧美一区 | 超碰人人在线观看 | 人人澡人人草 | 亚洲素人在线 | 97在线观视频免费观看 | 国产午夜精品无码一区二区 | 天堂中文在线免费观看 | 免费黄网在线观看 | 国产成人免费看 | 美女18网站 | 奇米狠狠去啦 | 国产小视频免费在线观看 | 欧美精品二区三区四区免费看视频 | 怡红院一区 | av自拍偷拍 | 在线观看免费高清视频 | 香蕉久久国产av一区二区 | 粉色视频免费观看 | 男人天堂视频在线观看 | 欧美乱色| 国产极品福利 | 黄色激情小说视频 | 中文字幕一区二区三区久久久 | 好吊色一区二区三区 | 亚洲成人资源 | www日韩欧美 | 日韩久久精品视频 | 国产人人射 | 中文字幕在线1 | 黄色1级大片| 欧美激情视频一区二区三区 | 性感av在线 | 劲爆欧美第一页 | 视频一区二区不卡 | 国产一区二区在线播放 | 国产一区综合 | 性高湖久久久久久久久aaaaa | 久久精品色妇熟妇丰满人妻 | 好看的黄色录像 | 日韩精品人妻中文字幕有码 | 18禁免费无码无遮挡不卡网站 | 午夜中出| 久久免费在线观看 | 视频一区 中文字幕 | 国产精品色婷婷99久久精品 | 久久视频热 | 中出在线视频 | 亚洲精品久久久久久无码色欲四季 | 欧美一级免费看 | 国产午夜精品一区二区 | 青青草视频在线观看 | 国产激情在线视频 | 欧美在线观看网站 | 亚洲a在线播放 | 久久国产热视频 | 男插女视频网站 | 成人免费淫片aa视频免费 | 秋霞国产| 黄色一级小视频 | 亚洲第一第二区 | 日韩成年人视频 | 毛片大全在线观看 | 成人在线一区二区三区 | 伊人操 | 丁香一区二区 | www黄色在线观看 | 青青青免费在线视频 | 亚洲久久综合 | 国产精品夜夜夜爽张柏芝 | 日本韩国欧美一区二区 | 清草视频| 国产一区二区三区精品在线观看 | 国产又爽又黄免费视频 | 99热这里只 | 久久伊人中文字幕 | 99久久国 | 91影院在线观看 | 国产手机在线 | 男人天堂导航 | 色图综合| 悟空影视大全免费高清观看在线 | 国产精品19乱码一区二区三区 | 91久久久久久| 亚洲国产美女视频 | www.欧美色图 | 国产按摩一区二区三区 | 夫妻精品 | 性激烈视频在线观看 | japan粗暴video蹂躏 | japansexxxxhd医生 夜夜操导航 | 又黄又爽又色的视频 | 国产亚洲欧美在线视频 | 亚洲成人精品一区二区 | 香蕉日日 | 少妇一级淫片免费放 |