成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

我把 ThreadLocal 能問(wèn)的,都寫了

開(kāi)發(fā) 前端
今天我們?cè)賮?lái)盤一盤 ThreadLocal ,這篇力求對(duì) ThreadLocal 一網(wǎng)打盡,徹底弄懂 ThreadLocal 的機(jī)制。

 [[419956]]

你好,我是yes。

今天我們?cè)賮?lái)盤一盤 ThreadLocal ,這篇力求對(duì) ThreadLocal 一網(wǎng)打盡,徹底弄懂 ThreadLocal 的機(jī)制。

有了這篇基礎(chǔ)之后,下篇再來(lái)盤一盤 ThreadLocal 的進(jìn)階版,等我哈。

話不多說(shuō),本文要解決的問(wèn)題如下:

  • 為什么需要 ThreadLocal
  • 應(yīng)該如何設(shè)計(jì) ThreadLocal
  • 從源碼看ThreadLocal 的原理
  • ThreadLocal 內(nèi)存泄露之為什么要用弱引用
  • ThreadLocal 的最佳實(shí)踐
  • InheritableThreadLocal

好了,開(kāi)車!

為什么需要 ThreadLocal

最近不是開(kāi)放三胎政策嘛,假設(shè)你有三個(gè)孩子。

現(xiàn)在你帶著三個(gè)孩子出去逛街,路過(guò)了玩具店,三個(gè)孩子都看中了一款變形金剛。

所以你買了一個(gè)變形金剛,打算讓三個(gè)孩子輪著玩。

回到家你發(fā)現(xiàn),孩子因?yàn)檫@個(gè)玩具吵架了,三個(gè)都爭(zhēng)著要玩,誰(shuí)也不讓著誰(shuí)。

這時(shí)候怎么辦呢?你可以去拉架,去講道理,說(shuō)服孩子輪流玩,但這很累。

所以一個(gè)簡(jiǎn)單的辦法就是出去再買兩個(gè)變形金剛,這樣三個(gè)孩子都有各自的變形金剛,世界就暫時(shí)得到了安寧。

映射到我們今天的主題,變形金剛就是共享變量,孩子就是程序運(yùn)行的線程。

有多個(gè)線程(孩子),爭(zhēng)搶同一個(gè)共享變量(玩具),就會(huì)產(chǎn)生沖突,而程序的解決辦法是加鎖(父母說(shuō)服,講道理,輪流玩),但加鎖就意味著性能的消耗(父母比較累)。

所以有一種解決辦法就是避免共享(讓每個(gè)孩子都各自擁有一個(gè)變形金剛),這樣線程之間就不需要競(jìng)爭(zhēng)共享變量(孩子之間就不會(huì)爭(zhēng)搶)。

所以為什么需要 ThreadLocal?

就是為了通過(guò)本地化資源來(lái)避免共享,避免了多線程競(jìng)爭(zhēng)導(dǎo)致的鎖等消耗。

這里需要強(qiáng)調(diào)一下,不是說(shuō)任何東西都能直接通過(guò)避免共享來(lái)解決,因?yàn)橛行r(shí)候就必須共享。

舉個(gè)例子:當(dāng)利用多線程同時(shí)累加一個(gè)變量的時(shí)候,此時(shí)就必須共享,因?yàn)橐粋€(gè)線程的對(duì)變量的修改需要影響要另個(gè)線程,不然累加的結(jié)果就不對(duì)了。

再舉個(gè)不需要共享的例子:比如現(xiàn)在每個(gè)線程需要判斷當(dāng)前請(qǐng)求的用戶來(lái)進(jìn)行權(quán)限判斷,那這個(gè)用戶信息其實(shí)就不需要共享,因?yàn)槊總€(gè)線程只需要管自己當(dāng)前執(zhí)行操作的用戶信息,跟別的用戶不需要有交集。

好了,道理很簡(jiǎn)單,這下子想必你已經(jīng)清晰了 ThreadLocal 出現(xiàn)的緣由了。

再來(lái)看一下 ThreadLocal 使用的小 demo。

  1. public class YesThreadLocal { 
  2.  
  3.     private static final ThreadLocal<String> threadLocalName = ThreadLocal.withInitial(() -> Thread.currentThread().getName()); 
  4.  
  5.     public static void main(String[] args) { 
  6.         for (int i = 0; i < 5; i++) { 
  7.             new Thread(() -> { 
  8.                 System.out.println("threadName: " + threadLocalName.get()); 
  9.             }, "yes-thread-" + i).start(); 
  10.         } 
  11.     } 

輸出結(jié)果如下:

可以看到,我在 new 線程的時(shí)候,設(shè)置了每個(gè)線程名,每個(gè)線程都操作同一個(gè) ThreadLocal 對(duì)象的 get 卻返回的各自的線程名,是不是很神奇?

應(yīng)該如何設(shè)計(jì) ThreadLocal ?

那應(yīng)該怎么設(shè)計(jì) ThreadLocal 來(lái)實(shí)現(xiàn)以上的操作,即本地化資源呢?

我們的目標(biāo)已經(jīng)明確了,就是用 ThreadLocal 變量來(lái)實(shí)現(xiàn)線程隔離。

從代碼上看,可能最直接的實(shí)現(xiàn)方法就是將 ThreadLocal 看做一個(gè) map ,然后每個(gè)線程是 key,這樣每個(gè)線程去調(diào)用 ThreadLocal.get 的時(shí)候,將自身作為 key 去 map 找,這樣就能獲取各自的值了。

聽(tīng)起來(lái)很完美?錯(cuò)了!

這樣 ThreadLocal 就變成共享變量了,多個(gè)線程競(jìng)爭(zhēng) ThreadLocal ,那就得保證 ThreadLocal 的并發(fā)安全,那就得加鎖了,這樣繞了一圈就又回去了。

所以這個(gè)方案不行,那應(yīng)該怎么做?

答案其實(shí)上面已經(jīng)講了,是需要在每個(gè)線程的本地都存一份值,說(shuō)白了就是每個(gè)線程需要有個(gè)變量,來(lái)存儲(chǔ)這些需要本地化資源的值,并且值有可能有多個(gè),所以怎么弄呢?

在線程對(duì)象內(nèi)部搞個(gè) map,把 ThreadLocal 對(duì)象自身作為 key,把它的值作為 map 的值。

這樣每個(gè)線程可以利用同一個(gè)對(duì)象作為 key ,去各自的 map 中找到對(duì)應(yīng)的值。

這不就完美了嘛!比如我現(xiàn)在有 3 個(gè) ThreadLocal 對(duì)象,2 個(gè)線程。

  1. ThreadLocal<String> threadLocal1 =  new ThreadLocal<>(); 
  2. ThreadLocal<Integer> threadLocal2 =  new ThreadLocal<>(); 
  3. ThreadLocal<Integer> threadLocal3 =  new ThreadLocal<>(); 

那此時(shí) ThreadLocal 對(duì)象和線程的關(guān)系如下圖所示:

這樣一來(lái)就滿足了本地化資源的需求,每個(gè)線程維護(hù)自己的變量,互不干擾,實(shí)現(xiàn)了變量的線程隔離,同時(shí)也滿足存儲(chǔ)多個(gè)本地變量的需求,完美!

JDK就是這樣實(shí)現(xiàn)的!我們來(lái)看看源碼。

從源碼看ThreadLocal 的原理

前面我們說(shuō)到 Thread 對(duì)象里面會(huì)有個(gè) map,用來(lái)保存本地變量。

我們來(lái)看下 jdk 的 Thread 實(shí)現(xiàn)

  1. ThreadLocal<String> threadLocal1 =  new ThreadLocal<>(); 
  2. ThreadLocal<Integer> threadLocal2 =  new ThreadLocal<>(); 
  3. ThreadLocal<Integer> threadLocal3 =  new ThreadLocal<>(); 

可以看到,確實(shí)有個(gè) map ,不過(guò)這個(gè) map 是 ThreadLocal 的靜態(tài)內(nèi)部類,記住這個(gè)變量的名字 threadLocals,下面會(huì)有用的哈。

看到這里,想必有很多小伙伴會(huì)產(chǎn)生一個(gè)疑問(wèn)。

竟然這個(gè) map 是放在 Thread 里面使用,那為什么要定義成 ThreadLocal 的靜態(tài)內(nèi)部類呢?

首先內(nèi)部類這個(gè)東西是編譯層面的概念,就像語(yǔ)法糖一樣,經(jīng)過(guò)編譯器之后其實(shí)內(nèi)部類會(huì)提升為外部頂級(jí)類,和平日里外部定義的類沒(méi)有區(qū)別,也就是說(shuō)在 JVM 中是沒(méi)有內(nèi)部類這個(gè)概念的。

一般情況下非靜態(tài)內(nèi)部類用在內(nèi)部類,跟其他類無(wú)任何關(guān)聯(lián),專屬于這個(gè)外部類使用,并且也便于調(diào)用外部類的成員變量和方法,比較方便。

而靜態(tài)外部類其實(shí)就等于一個(gè)頂級(jí)類,可以獨(dú)立于外部類使用,所以更多的只是表明類結(jié)構(gòu)和命名空間。

所以說(shuō)這樣定義的用意就是說(shuō)明 ThreadLocalMap 是和 ThreadLocal 強(qiáng)相關(guān)的,專用于保存線程本地變量。

現(xiàn)在我們來(lái)看一下 ThreadLocalMap 的定義:

重點(diǎn)我已經(jīng)標(biāo)出來(lái)了,首先可以看到這個(gè) ThreadLocalMap 里面有個(gè) Entry 數(shù)組,熟悉 HashMap 的小伙伴可能有點(diǎn)感覺(jué)了。

這個(gè) Entry 繼承了 WeakReference 即弱引用。這里需要注意,不是說(shuō) Entry 自己是弱引用,看到我標(biāo)注的 Entry 構(gòu)造函數(shù)的 super(k) 沒(méi),這個(gè) key 才是弱引用。

所以 ThreadLocalMap 里有個(gè) Entry 的數(shù)組,這個(gè) Entry 的 key 就是 ThreadLocal 對(duì)象,value 就是我們需要保存的值。

那是如何通過(guò) key 在數(shù)組中找到 Entry 然后得到 value 的呢 ?

這就要從上面的 threadLocalName.get()說(shuō)起,不記得這個(gè)代碼的滑上去看下示例,其實(shí)就是調(diào)用 ThreadLocal 的 get 方法。

此時(shí)就進(jìn)入 ThreadLocal#get方法中了,這里就可以得知為什么不同的線程對(duì)同一個(gè) ThreadLocal 對(duì)象調(diào)用 get 方法竟然能得到不同的值了。

這個(gè)中文注釋想必很清晰了吧!

ThreadLocal#get方法首先獲取當(dāng)前線程,然后得到當(dāng)前線程的 ThreadLocalMap 變量即 threadLocals,然后將自己作為 key 從 ThreadLocalMap 中找到 Entry ,最終返回 Entry 里面的 value 值。

這里我們?cè)倏匆幌?key 是如何從 ThreadLocalMap 中找到 Entry 的,即map.getEntry(this)是如何實(shí)現(xiàn)的,其實(shí)很簡(jiǎn)單。

可以看到 ThreadLocalMap 雖然和 HashMap 一樣,都是基于數(shù)組實(shí)現(xiàn)的,但是它們對(duì)于 Hash 沖突的解決方法不一樣。

HashMap 是通過(guò)鏈表(紅黑樹(shù))法來(lái)解決沖突,而 ThreadLocalMap 是通過(guò)開(kāi)放尋址法來(lái)解決沖突。

聽(tīng)起來(lái)好像很高級(jí),其實(shí)道理很簡(jiǎn)單,我們來(lái)看一張圖就很清晰了。

所以說(shuō),如果通過(guò) key 的哈希值得到的下標(biāo)無(wú)法直接命中,則會(huì)將下標(biāo) +1,即繼續(xù)往后遍歷數(shù)組查找 Entry ,直到找到或者返回 null。

可以看到,這種 hash 沖突的解決效率其實(shí)不高,但是一般 ThreadLocal 也不會(huì)太多,所以用這種簡(jiǎn)單的辦法解決即可。

至于代碼中的expungeStaleEntry我們等下再分析,先來(lái)看下 ThreadLocalMap#set 方法,看看寫入的怎樣實(shí)現(xiàn)的,來(lái)看看 hash 沖突的解決方法是否和上面說(shuō)的一致。

可以看到 set 的邏輯也很清晰。

先通過(guò) key 的 hash 值計(jì)算出一個(gè)數(shù)組下標(biāo),然后看看這個(gè)下標(biāo)是否被占用了,如果被占了看看是否就是要找的 Entry 。

如果是則進(jìn)行更新,如果不是則下標(biāo)++,即往后遍歷數(shù)組,查找下一個(gè)位置,找到空位就 new 個(gè) Entry 然后把坑給占用了。

當(dāng)然,這種數(shù)組操作一般免不了閾值的判斷,如果超過(guò)閾值則需要進(jìn)行擴(kuò)容。

上面的清理操作和 key 為空的情況,下面再做分析,這里先略過(guò)。

至此,我們已經(jīng)分析了 ThreadLocalMap 的核心操作 get 和 set ,想必你對(duì) ThreadLocalMap 的原理已經(jīng)從源碼層面清晰了!

可能有些小伙伴對(duì) key 的哈希值的來(lái)源有點(diǎn)疑惑,所以我再來(lái)補(bǔ)充一下 key.threadLocalHashCode的分析。

可以看到key.threadLocalHashCode其實(shí)就是調(diào)用 nextHashCode 進(jìn)行一個(gè)原子類的累加。

注意看上面都是靜態(tài)變量和靜態(tài)方法,所以在 ThreadLocal 對(duì)象之間是共享的,然后通過(guò)固定累加一個(gè)奇怪的數(shù)字0x61c88647來(lái)分配 hash 值。

這個(gè)數(shù)字當(dāng)然不是亂寫的,是實(shí)驗(yàn)證明的一個(gè)值,即通過(guò) 0x61c88647 累加生成的值與 2 的冪取模的結(jié)果,可以較為均勻地分布在 2 的冪長(zhǎng)度的數(shù)組中,這樣可以減少 hash 沖突。

有興趣的小伙伴可以深入研究一下,反正我沒(méi)啥興趣。

ThreadLocal 內(nèi)存泄露之為什么要用弱引用

接下來(lái)就是要解決上面挖的坑了,即 key 的弱引用、Entry 的 key 為什么可能為 null、還有清理 Entry 的操作。

之前提到過(guò),Entry 對(duì) key 是弱引用,那為什么要弱引用呢?

我們知道,如果一個(gè)對(duì)象沒(méi)有強(qiáng)引用,只有弱引用的話,這個(gè)對(duì)象是活不過(guò)一次 GC 的,所以這樣的設(shè)計(jì)就是為了讓當(dāng)外部沒(méi)有對(duì) ThreadLocal 對(duì)象有強(qiáng)引用的時(shí)候,可以將 ThreadLocal 對(duì)象給清理掉。

那為什么要這樣設(shè)計(jì)呢?

假設(shè) Entry 對(duì) key 的引用是強(qiáng)引用,那么來(lái)看一下這個(gè)引用鏈:

從這條引用鏈可以得知,如果線程一直在,那么相關(guān)的 ThreadLocal 對(duì)象肯定會(huì)一直在,因?yàn)樗恢北粡?qiáng)引用著。

看到這里,可能有人會(huì)說(shuō)那線程被回收之后就好了呀。

重點(diǎn)來(lái)了!線程在我們應(yīng)用中,常常是以線程池的方式來(lái)使用的,比如 Tomcat 的線程池處理了一堆請(qǐng)求,而線程池中的線程一般是不會(huì)被清理掉的,所以這個(gè)引用鏈就會(huì)一直在,那么 ThreadLocal 對(duì)象即使沒(méi)有用了,也會(huì)隨著線程的存在,而一直存在著!

所以這條引用鏈需要弱化一下,而能操作的只有 Entry 和 key 之間的引用,所以它們之間用弱引用來(lái)實(shí)現(xiàn)。

與之對(duì)應(yīng)的還有一個(gè)條引用鏈,我結(jié)合著上面的線程引用鏈都畫出來(lái):

另一條引用鏈就是棧上的 ThreadLocal 引用指向堆中的 ThreadLocal 對(duì)象,這個(gè)引用是強(qiáng)引用。

如果有這條強(qiáng)引用存在,那說(shuō)明此時(shí)的 ThreadLocal 是有用的,此時(shí)如果發(fā)生 GC 則 ThreadLocal 對(duì)象不會(huì)被清除,因?yàn)橛袀€(gè)強(qiáng)引用存在。

當(dāng)隨著方法的執(zhí)行完畢,相應(yīng)的棧幀也出棧了,此時(shí)這條強(qiáng)引用鏈就沒(méi)了,如果沒(méi)有別的棧有對(duì) ThreadLocal 對(duì)象的引用,那么說(shuō)明 ThreadLocal 對(duì)象無(wú)法再被訪問(wèn)到(定義成靜態(tài)變量的另說(shuō))。

那此時(shí) ThreadLocal 只存在與 Entry 之間的弱引用,那此時(shí)發(fā)生 GC 它就可以被清除了,因?yàn)樗鼰o(wú)法被外部使用了,那就等于沒(méi)用了,是個(gè)垃圾,應(yīng)該被處理來(lái)節(jié)省空間。

至此,想必你已經(jīng)明白為什么 Entry 和 key 之間要設(shè)計(jì)為弱引用,就是因?yàn)槠饺站€程的使用方式基本上都是線程池,所以線程的生命周期就很長(zhǎng),可能從你部署上線后一直存在,而 ThreadLocal 對(duì)象的生命周期可能沒(méi)這么長(zhǎng)。

所以為了能讓已經(jīng)沒(méi)用 ThreadLocal 對(duì)象得以回收,所以 Entry 和 key 要設(shè)計(jì)成弱引用,不然 Entry 和 key是強(qiáng)引用的話,ThreadLocal 對(duì)象就會(huì)一直在內(nèi)存中存在。

但是這樣設(shè)計(jì)就可能產(chǎn)生內(nèi)存泄漏。

那什么叫內(nèi)存泄漏?

就是指:程序中已經(jīng)無(wú)用的內(nèi)存無(wú)法被釋放,造成系統(tǒng)內(nèi)存的浪費(fèi)。

當(dāng) Entry 中的 key 即 ThreadLocal 對(duì)象被回收了之后,會(huì)發(fā)生 Entry 中 key 為 null 的情況,其實(shí)這個(gè) Entry 就已經(jīng)沒(méi)用了,但是又無(wú)法被回收,因?yàn)橛?Thread->ThreadLocalMap ->Entry 這條強(qiáng)引用在,這樣沒(méi)用的內(nèi)存無(wú)法被回收就是內(nèi)存泄露。

那既然會(huì)有內(nèi)存泄漏還這樣實(shí)現(xiàn)?

這里就要填一填上面的坑了,也就是涉及到的關(guān)于 expungeStaleEntry即清理過(guò)期的 Entry 的操作。

設(shè)計(jì)者當(dāng)然知道會(huì)出現(xiàn)這種情況,所以在多個(gè)地方都做了清理無(wú)用 Entry ,即 key 已經(jīng)被回收的 Entry 的操作。

比如通過(guò) key 查找 Entry 的時(shí)候,如果下標(biāo)無(wú)法直接命中,那么就會(huì)向后遍歷數(shù)組,此時(shí)遇到 key 為 null 的 Entry 就會(huì)清理掉,再貼一下這個(gè)方法:

這個(gè)方法也很簡(jiǎn)單,我們來(lái)看一下它的實(shí)現(xiàn):

所以在查找 Entry 的時(shí)候,就會(huì)順道清理無(wú)用的 Entry ,這樣就能防止一部分的內(nèi)存泄露啦!

還有像擴(kuò)容的時(shí)候也會(huì)清理無(wú)用的 Entry:

其它還有,我就不貼了,反正知曉設(shè)計(jì)者是做了一些操作來(lái)回收無(wú)用的 Entry 的即可。

ThreadLocal 的最佳實(shí)踐

當(dāng)然,等著這些操作被動(dòng)回收不是最好的方法,假設(shè)后面沒(méi)人調(diào)用 get 或者調(diào)用 get 都直接命中或者不會(huì)發(fā)生擴(kuò)容,那無(wú)用的 Entry 豈不是一直存在了嗎?所以上面說(shuō)只能防止一部分的內(nèi)存泄露。

所以,最佳實(shí)踐是用完了之后,調(diào)用一下 remove 方法,手工把 Entry 清理掉,這樣就不會(huì)發(fā)生內(nèi)存泄漏了!

  1. void yesDosth { 
  2.  threadlocal.set(xxx); 
  3.  try { 
  4.   // do sth 
  5.  } finally { 
  6.   threadlocal.remove(); 
  7.  } 

這就是使用 Threadlocal 的一個(gè)正確姿勢(shì)啦,即不需要的時(shí)候,顯示的 remove 掉。

當(dāng)然,如果不是線程池使用方式的話,其實(shí)不用關(guān)系內(nèi)存泄漏,反正線程執(zhí)行完了就都回收了,但是一般我們都是使用線程池的,可能只是你沒(méi)感覺(jué)到。

比如你用了 tomcat ,其實(shí)請(qǐng)求的執(zhí)行用的就是 tomcat 的線程池,這就是隱式使用。

還有一個(gè)問(wèn)題,關(guān)于 withInitial 也就是初始化值的方法。

由于類似 tomcat 這種隱式線程池的存在,即線程第一次調(diào)用執(zhí)行 Threadlocal 之后,如果沒(méi)有顯示調(diào)用 remove 方法,則這個(gè) Entry 還是存在的,那么下次這個(gè)線程再執(zhí)行任務(wù)的時(shí)候,不會(huì)再調(diào)用 withInitial 方法,也就是說(shuō)會(huì)拿到上一次執(zhí)行的值。

但是你以為執(zhí)行任務(wù)的是新線程,會(huì)初始化值,然而它是線程池里面的老線程,這就和預(yù)期不一致了,所以這里需要注意。

InheritableThreadLocal

這個(gè)其實(shí)之前文章寫過(guò)了,不過(guò)這次竟然寫了 threadlocal 就再拿出來(lái)。

這玩意可以理解為就是可以把父線程的 threadlocal 傳遞給子線程,所以如果要這樣傳遞就用 InheritableThreadLocal ,不要用 threadlocal。

原理其實(shí)很簡(jiǎn)單,在 Thread 中已經(jīng)包含了這個(gè)成員:

在父線程創(chuàng)建子線程的時(shí)候,子線程的構(gòu)造函數(shù)可以得到父線程,然后判斷下父線程的 InheritableThreadLocal 是否有值,如果有的話就拷過(guò)來(lái)。

這里要注意,只會(huì)在線程創(chuàng)建的時(shí)會(huì)拷貝 InheritableThreadLocal 的值,之后父線程如何更改,子線程都不會(huì)受其影響。

最后

至此有關(guān) ThreadLocal 的知識(shí)點(diǎn)就差不多了。

想必你已經(jīng)清楚 ThreadLocal 的原理,包括如何實(shí)現(xiàn),為什么 key 要設(shè)計(jì)成弱引用,并且關(guān)于在線程池中使用的注意點(diǎn)等等。

其實(shí)本沒(méi)打算寫 ThreadLocal 的,因?yàn)樽罱诳?Netty ,所以想寫一下 FastThreadLocal ,但是前置知識(shí)點(diǎn)是 ThreadLocal ,所以就干了這篇。

消化了這篇之后,出去面試 ThreadLocal 算是沒(méi)問(wèn)題了吧,最后再留個(gè)小小的思考題。

那為什么 Entry 中的 value 不弱引用?

這個(gè)題目來(lái)自群友的一個(gè)面試題哈,想必看完這篇文章之后,這個(gè)題目難不倒你,歡迎留言區(qū)寫出答案!

等我下篇的 ThreadLocal 進(jìn)階版!

責(zé)任編輯:武曉燕 來(lái)源: yes的練級(jí)攻略
相關(guān)推薦

2020-07-27 08:13:03

RabbitMQ代碼系統(tǒng)

2021-01-19 05:24:36

ThreadLocal線程編程

2022-05-14 21:19:22

ThreadLocaJDKsynchroniz

2022-11-04 08:47:52

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

2020-07-28 08:59:22

JavahreadLocal面試

2023-11-02 08:27:29

2021-01-26 05:07:53

WindowViewWMS

2023-03-27 08:03:46

ChatGPTMidjourney主角

2020-09-11 06:39:29

ThreadLocal線程

2022-04-01 12:40:13

MySQL數(shù)據(jù)庫(kù)

2022-12-08 17:12:34

注解源碼場(chǎng)景

2024-02-06 07:56:20

數(shù)據(jù)庫(kù)分布式數(shù)據(jù)庫(kù)架構(gòu)產(chǎn)品

2024-03-13 07:53:57

弱引用線程工具

2022-01-24 14:08:16

Redis面試命令

2015-11-16 14:52:13

代碼程序員

2019-11-20 10:38:36

路由路由協(xié)議路由器

2020-05-15 09:30:12

代碼函數(shù)語(yǔ)言

2022-04-01 08:37:07

SpringAPI前端

2019-01-21 15:00:51

面試前端開(kāi)發(fā)

2023-11-03 08:10:49

ThreadLoca內(nèi)存泄露
點(diǎn)贊
收藏

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

主站蜘蛛池模板: 99热播精品| 91伊人网 | 性生生活大片免费看视频 | 精品一区二区三区中文字幕 | 日韩欧美不卡 | 黑人巨大精品欧美黑白配亚洲 | 超碰人人91| 爱操影视| 国产激情精品一区二区三区 | 成人深夜福利网站 | 亚洲情综合五月天 | 国产高清免费视频 | 欧美中文在线 | 欧美一区二区激情三区 | 久久国产精品偷 | 亚洲精品久久久久中文字幕欢迎你 | 成年人网站在线观看视频 | 亚洲第一区国产精品 | 草比网站| 在线中文一区 | 国产二区精品视频 | 欧美在线一区二区三区 | 天天天操| 欧美性生活一区二区三区 | 国产精品久久久久久久久免费樱桃 | 亚洲国产精品美女 | 天天爽夜夜爽精品视频婷婷 | 中文字幕一区二区三区精彩视频 | 91一区 | 91久久国产 | 欧美国产精品久久久 | 亚洲免费视频播放 | 欧美日韩国产中文 | 97国产在线观看 | 欧美黄在线观看 | www视频在线观看 | 色接久久 | 91久久久久久 | 青青久在线视频 | 久久91精品国产一区二区三区 | 日韩精品在线观看一区二区三区 |