自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

嘮點(diǎn)面試官愛聽的系列之ThreadLocal

開發(fā) 前端
ThreadLocal 是 Java 中的一個(gè)類,用于創(chuàng)建線程局部變量。每個(gè)線程對(duì) ThreadLocal 變量的訪問都是獨(dú)立的,每個(gè)線程都會(huì)擁有自己獨(dú)立的副本。

面試官:“看你簡(jiǎn)歷寫了熟悉 Java 并發(fā)編程,那你給我講講 ThreadLocal 吧?!?/p>

我:“ThreadLocal 是 Java 中的一個(gè)類,用于創(chuàng)建線程局部變量。每個(gè)線程對(duì) ThreadLocal 變量的訪問都是獨(dú)立的,每個(gè)線程都會(huì)擁有自己獨(dú)立的副本?!?/p>

完蛋,這么嘮,面試官一看就是背的八股,一點(diǎn)自己的東西都沒有。

你得嘮點(diǎn)面試官愛聽的,要有一定深度,讓面試官看出自己的思考。

下面我先來打個(gè)樣。

我在實(shí)際開發(fā)項(xiàng)目有利用過 ThreadLocal 存儲(chǔ)用戶信息,并對(duì) ThreadLocal 源碼有過一定研究。

ThreadLocal 的優(yōu)勢(shì)是無鎖化提升并發(fā)性能和簡(jiǎn)化變量的傳遞邏輯,每個(gè)線程對(duì) ThreadLocal 變量的訪問都是獨(dú)立的,每個(gè)線程都會(huì)擁有自己獨(dú)立的副本。

我:“需要我展開聊聊嗎?”

面試官:“好的?!?/p>

ThreadLocal 存儲(chǔ)的變量實(shí)際上是存儲(chǔ)在 Thread 線程對(duì)象中,在 Thread 類中有兩個(gè) ThreadLocalMap 類型的變量一個(gè)是 threadLocals,另一個(gè)是 inheritableThreadLocals。

其中 threadLocals 就是用于存儲(chǔ) ThreadLocal 對(duì)應(yīng)的變量。ThreadLocalMap 也是哈希數(shù)據(jù)結(jié)構(gòu),不過與我們用的最多的 HashMap 有所不同。

ThreadLocalMap 解決哈希沖突采用的是線性探測(cè)法,而 HashMap 采用的是拉鏈法。

ThreadLocalMap 的初始容量是 16,當(dāng)負(fù)載達(dá)到 2/3 的時(shí)候會(huì)觸發(fā)擴(kuò)容邏輯,擴(kuò)容的時(shí)候容量*2。

ThreadLocalMap 通過 Entry 數(shù)組存儲(chǔ)數(shù)據(jù)。每一個(gè) Entry 對(duì)象的 key 是一個(gè)弱引用指向的 ThreadLocal 對(duì)象。值是一個(gè)強(qiáng)引用的對(duì)象,類型由 ThreadLocal 對(duì)象的泛型 <> 決定。

在 Entry 對(duì)象中 ThreadLocal 之所以使用弱引用進(jìn)行鏈接是為了減少當(dāng)內(nèi)存泄露發(fā)生時(shí)所帶來的內(nèi)存損失。

一旦 ThreadLocal 對(duì)象失去了外界強(qiáng)引用,在發(fā)生垃圾回收時(shí)僅被 Entry 對(duì)象弱引用的 ThreadLocal 對(duì)象就會(huì)被垃圾回收器回收,這時(shí)該 Entry 對(duì)象就是所謂的過時(shí) Entry。

過時(shí) Entry 自身及其引用的 vlaue 值在其它 ThreadLocal 對(duì)象執(zhí)行 get、set、remove 方法時(shí),可能會(huì)被清理,從而釋放泄露的內(nèi)存。

當(dāng)然在實(shí)際開發(fā)中,我們更應(yīng)該主動(dòng)在恰當(dāng)時(shí)機(jī)調(diào)用 remove 方法,對(duì)不再使用的 ThreadLocal 對(duì)象進(jìn)行清理,避免觸發(fā) ThreadLocal 的清理機(jī)制,進(jìn)而提升 get、set、remove 方法的執(zhí)行效率。

需要注意的一點(diǎn),我們通常所使用的 web 容器 tomcat 對(duì)工作線程的管理使用了池化技術(shù),也就是說 Thread 對(duì)象會(huì)被重復(fù)使用。

如果我們?cè)谝粋€(gè)請(qǐng)求結(jié)束的時(shí)候沒有調(diào)用 remove 方法清理 ThreadLocal 對(duì)象,并且其他請(qǐng)求在執(zhí)行 get 方法前沒有執(zhí)行 set 方法進(jìn)行設(shè)置值,那么可能會(huì)發(fā)生匪夷所思的業(yè)務(wù)異常。

咦?為什么當(dāng)前是 A 發(fā)起的請(qǐng)求,獲取到的卻是 B 的信息?

圖片圖片

ThreadLocal 類有一個(gè)子類叫做 InheritableThreadLocal,InheritableThreadLocal 主要解決在單次請(qǐng)求過程中涉及到了多線程異步處理邏輯時(shí),ThreadLocal 變量無法傳遞問題。

雙十一有一個(gè)比價(jià)需求,需要拉取同商品在拼多多、淘寶、京東、抖音上的價(jià)格進(jìn)行比價(jià),如果采用單線程去執(zhí)行,需要依次進(jìn)行調(diào)用,該接口總耗時(shí)為獲取各大平臺(tái)價(jià)格耗時(shí)的累加和。

此時(shí)要想提高接口執(zhí)行效率可以采取多線程方案,但是在獲取各大平臺(tái)優(yōu)惠價(jià)時(shí)需要獲取 ThreadLocal 中存儲(chǔ)的上下文信息。

但是,我們前面說過 ThreadLocal 儲(chǔ)存的上下文,其實(shí)是存儲(chǔ)在了 Thread 對(duì)象中。

而采取多線程方案時(shí),獲取各大平臺(tái)價(jià)格的線程并不是之前的主線程,這時(shí)是無法直接通過 ThreadLocal 的 get 方法獲取到在主線程存儲(chǔ)的上下文信息。

此時(shí)怎么辦呢?有兩種方案,第一種是在開啟多線程之前先取出上下文信息,然后作為參數(shù)傳遞給每一個(gè)線程,但是這不是與 ThreadLocal 簡(jiǎn)化變量的傳遞邏輯的初衷相悖了嗎?

通過 InheritableThreadLocal 就可以很好的解決這個(gè)問題,在線程初始化的時(shí)候,當(dāng)前線程的 inheritableThreadLocals 會(huì)拷貝給新創(chuàng)建線程的 inheritableThreadLocals。

inheritableThreadLocals 就是上文提到的 Thread 線程對(duì)象中的另外一個(gè) ThreadLocalMap 類型變量,用于存儲(chǔ) InheritableThreadLocal 記錄的信息。

圖片圖片

我:“以上就是我對(duì) ThreadLocal 的一些認(rèn)識(shí)?!?/p>

內(nèi)心甚至期盼著面試官繼續(xù)深究,看過源碼解讀系列完全不慌!

想要進(jìn)行一步了解 ThreadLocal 的小伙伴可以回看 ThreadLocal 源碼解讀系列。

責(zé)任編輯:武曉燕 來源: Java極客技術(shù)
相關(guān)推薦

2024-09-24 10:28:22

2022-10-25 10:20:31

線程變量原理

2022-11-04 08:47:52

底層算法數(shù)據(jù)

2024-03-13 07:53:57

弱引用線程工具

2021-05-31 11:43:19

B-樹MySQL索引

2021-06-02 10:23:06

索引B+樹數(shù)據(jù)

2021-03-03 17:26:45

面試Synchronous底層

2015-08-13 10:29:12

面試面試官

2020-11-30 11:01:34

反射用途實(shí)現(xiàn)

2022-05-23 08:43:02

BigIntJavaScript內(nèi)置對(duì)象

2010-08-12 16:28:35

面試官

2023-02-16 08:10:40

死鎖線程

2018-10-22 14:28:26

面試官數(shù)據(jù)公司

2024-06-13 08:01:19

2021-11-08 09:18:01

CAS面試場(chǎng)景

2024-11-19 15:13:02

2023-12-27 18:16:39

MVCC隔離級(jí)別幻讀

2025-03-10 00:00:00

property?attributeHTML

2025-04-16 00:00:01

JWT客戶端存儲(chǔ)加密令

2025-04-08 00:00:00

@AsyncSpring異步
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)