0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

ThreadLocal的短板,我TTL來(lái)補(bǔ)!

jf_ro2CN3Fa ? 來(lái)源:芋道源碼 ? 2023-09-27 16:22 ? 次閱讀


有小伙伴讓我再說(shuō)說(shuō)TransmittableThreadLocal(下邊統(tǒng)一簡(jiǎn)稱:TTL),它是阿里開(kāi)源的一個(gè)工具類,解決異步執(zhí)行時(shí)上下文傳遞的問(wèn)題。

那今天就來(lái)介紹介紹 TTL,補(bǔ)充下 ThreadLocal 家族的短板吧。

這篇過(guò)后,ThreadLocal 就真的一網(wǎng)打盡了!

不過(guò)還是建議先看看前置篇(文末會(huì)放鏈接),不然理解起來(lái)可能有點(diǎn)困難。

緣由

任何一個(gè)組件的出現(xiàn)必有其緣由,知其緣由背景才能更深刻地理解它。

我們知道 ThreadLocal 的出現(xiàn)就是為了本地化線程資源,防止不必要的多線程之間的競(jìng)爭(zhēng)。

在有些場(chǎng)景,當(dāng)父線程 new 一個(gè)子線程的時(shí)候,希望把它的 ThreadLocal 繼承給子線程。

這時(shí)候 InheritableThreadLocal 就來(lái)了,它就是為了父子線程傳遞本地化資源而提出的。

具體的實(shí)現(xiàn)是在子線程對(duì)象被 new 的時(shí)候,即 Thread.init 的時(shí),如果查看到父線程內(nèi)部有 InheritableThreadLocal 的數(shù)據(jù)。

那就在子 Thread 初始化的時(shí),把父線程的 InheritableThreadLocal 拷貝給子線程。

141edfde-5cd6-11ee-939d-92fbcf53809c.png

就這樣簡(jiǎn)單地把父線程的 ThreadLocal 數(shù)據(jù)傳遞給子線程了。

但是,這個(gè)場(chǎng)景只能發(fā)生在 new Thread 的時(shí)候!也就是手動(dòng)創(chuàng)建線程之時(shí)!那就有個(gè)問(wèn)題了,在平時(shí)我們使用的時(shí)候基本用的都是線程池。

那就麻了啊,線程池里面的線程都預(yù)創(chuàng)建好了,調(diào)用的時(shí)候就沒(méi)法直接用 InheritableThreadLocal 了。

所以就產(chǎn)生了一個(gè)需求,如何往線程池內(nèi)的線程傳遞 ThreadLocal?,JDK 的類庫(kù)沒(méi)這個(gè)功能,所以怎么搞?

只能我們自己造輪子了。

基于 Spring Boot + MyBatis Plus + Vue & Element 實(shí)現(xiàn)的后臺(tái)管理系統(tǒng) + 用戶小程序,支持 RBAC 動(dòng)態(tài)權(quán)限、多租戶、數(shù)據(jù)權(quán)限、工作流、三方登錄、支付、短信、商城等功能

  • 項(xiàng)目地址:https://github.com/YunaiV/ruoyi-vue-pro
  • 視頻教程:https://doc.iocoder.cn/video/

如何設(shè)計(jì)?

需求已經(jīng)明確了,但是怎么實(shí)現(xiàn)呢?

平時(shí)我們用線程池的話,比如你要提交任務(wù),則使用代碼如下:

Runnabletask=newRunnable....;
executorService.submit(task);

小貼士:以下的 ThreadLocal 泛指線程本地?cái)?shù)據(jù),不是指 ThreadLocal 這個(gè)類

這時(shí)候,我們想著把當(dāng)前線程的 ThreadLocal 傳遞給線程池內(nèi)部將要執(zhí)行這個(gè) task 的線程。

但此時(shí)我們哪知道線程池里面的哪個(gè)線程會(huì)來(lái)執(zhí)行這個(gè)任務(wù)?

所以,我們得先把當(dāng)前線程的 ThreadLocal 保存到這個(gè) task 中。

然后當(dāng)線程池里的某個(gè)線程,比如線程 A 獲取這個(gè)任務(wù)要執(zhí)行的時(shí)候,看看 task 里面是否有存儲(chǔ)著的 ThreadLocal 。

如果存著那就把這個(gè) ThreadLocal 放到線程 A 的本地變量里,這樣就完成了傳遞。

然后還有一步,也挺關(guān)鍵的,就是恢復(fù)線程池內(nèi)部執(zhí)行線程的上下文,也就是該任務(wù)執(zhí)行完畢之后,把任務(wù)帶來(lái)的本地?cái)?shù)據(jù)給刪了,把線程以前的本地?cái)?shù)據(jù)復(fù)原。

143073d4-5cd6-11ee-939d-92fbcf53809c.png

設(shè)計(jì)思路應(yīng)該已經(jīng)很明確了吧?來(lái)看看具體需要如何實(shí)現(xiàn)吧!

基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 實(shí)現(xiàn)的后臺(tái)管理系統(tǒng) + 用戶小程序,支持 RBAC 動(dòng)態(tài)權(quán)限、多租戶、數(shù)據(jù)權(quán)限、工作流、三方登錄、支付、短信、商城等功能

  • 項(xiàng)目地址:https://github.com/YunaiV/yudao-cloud
  • 視頻教程:https://doc.iocoder.cn/video/

如何實(shí)現(xiàn)?

把上面的設(shè)計(jì)簡(jiǎn)單地、直白地翻譯成代碼如下:

1446c508-5cd6-11ee-939d-92fbcf53809c.png

如果你讀過(guò)我之前分析 ThreadLocal 的文章,應(yīng)該可以很容易的理解上面的操作。

這樣雖然可以實(shí)現(xiàn),但是可操作性太差,耦合性太高。

所以我們得想想怎么優(yōu)化一下,其實(shí)有個(gè)設(shè)計(jì)模式就很合適,那就是裝飾器模式。

我們可以自己搞一個(gè) Runnable 類,比如 YesRunnable,然后在 new YesRunnable 的時(shí)候,在構(gòu)造器里面把當(dāng)前線程的 threadlocal 賦值進(jìn)去。

然后 run 方法那里也修飾一下,我們直接看看偽代碼:

publicYesRunnable(Runnablerunable){
this.threadlocalCopy=copyFatherThreadlocal();
this.runable=runable;
}
publicvoidrun(){
//塞入父threadlocal,并返回當(dāng)前線程原先threadlocal
 Object backup = setThreadlocal(threadlocalCopy);
try{
 runable.run();//執(zhí)行被裝飾的任務(wù)邏輯
}finally{
restore(backup);//復(fù)原當(dāng)前線程的上下文
}
}

使用方式如下:

Runnabletask=()->{...};
YesRunnableyesRunnable=newYesRunnable(task);
executorService.submit(yesRunnable);

你看,這不就實(shí)現(xiàn)我們上面的設(shè)計(jì)了嘛!

不過(guò)還有一個(gè)點(diǎn)沒(méi)有揭秘,就是如何實(shí)現(xiàn) copyFatherThreadlocal。

我們?nèi)绾蔚弥妇€程現(xiàn)在到底有哪些 Threadlocal?并且哪些是需要上下文傳遞的?

所以我們還需要?jiǎng)?chuàng)建一個(gè)類來(lái)繼承 Threadlocal。

比如叫 YesThreadlocal,用它聲明的變量就表明需要父子傳遞的!

publicclassYesThreadlocal<T>extendsThreadLocal<T>

然后我們需要搞個(gè)地方來(lái)存儲(chǔ)當(dāng)前父線程上下文用到的所有 YesThreadlocal,這樣在 copyFatherThreadlocal的時(shí)候我們才好遍歷復(fù)制對(duì)吧?

我們可以搞個(gè) holder 來(lái)保存這些 YesThreadlocal ,不過(guò) holder 變量也得線程隔離。

畢竟每個(gè)線程所要使用的 YesThreadlocal 都不一樣,所以需要用 ThreadLocal 來(lái)修飾 holder 。

然后 YesThreadlocal 可能會(huì)有很多,我們可以用 set 來(lái)保存。

但是為了防止我們搞的這個(gè) holder 造成內(nèi)存泄漏的風(fēng)險(xiǎn),我們需要弱引用它,不過(guò)沒(méi)有 WeakHashSet,那我們就用 WeakHashMap 來(lái)替代存儲(chǔ)。

privatestaticfinalThreadLocal,?>>holder=new.....

這樣我們就打造了一個(gè)變量,它是線程獨(dú)有的,且又能拿來(lái)存儲(chǔ)當(dāng)前線程用到的所有 YesThreadLocal ,便于后面的復(fù)制,且又不會(huì)造成內(nèi)存泄漏(弱引用)。

是不是感覺(jué)有點(diǎn)暫時(shí)理不清?沒(méi)事,我們繼續(xù)來(lái)看看具體怎么用上這個(gè) hold ,可能會(huì)清晰些。

首先我們將需要傳遞給線程池的本地變量從 ThreadLocal 替換成 YesThreadLocal。

然后重寫 set 方法,實(shí)現(xiàn)如下:

@Override
publicfinalvoidset(Tvalue){
super.set(value);//調(diào)用ThreadLocal的set
addThisToHolder();//把當(dāng)前的 YesThreadLocal 對(duì)象塞入 hold 中。
}
privatevoidaddThisToHolder(){
if(!holder.get().containsKey(this)){
holder.get().put((YesThreadLocal)this,null);
}
}

			

你看這樣就把所有用到的 YesThreadLocal 塞到 holder 中了,然后再來(lái)看看 copyFatherThreadlocal 應(yīng)該如何實(shí)現(xiàn)。

privatestaticHashMap,Object>copyFatherThreadlocal(){
HashMap,Object>fatherMap=newHashMap,Object>();
for(YesThreadLocalthreadLocal:YesThreadLocal.holder.get().keySet()){
fatherMap.put(threadLocal,threadLocal.copyValue());
}
returnfatherMap;
}

			

邏輯很簡(jiǎn)單,就是一個(gè) map 遍歷拷貝。

我現(xiàn)在用一段話來(lái)小結(jié)一下,把上面的全部操作聯(lián)合起來(lái)理解,應(yīng)該會(huì)清晰很多。

實(shí)現(xiàn)思路小結(jié)

1.新建一個(gè) YesThreadLocal 類繼承自 ThreadLocal ,用于標(biāo)識(shí)這個(gè)修飾的變量需要父子線程拷貝

2.新建一個(gè) YesRunnable 類繼承自 Runnable,采用裝飾器模式,這樣就不用修改原有的 Runnable。在構(gòu)造階段復(fù)制父線程的 YesThreadLocal 變量賦值給 YesRunnable 的一個(gè)成員變量 threadlocalCopy 保存。

3.并修飾 YesRunnable#run 方法,在真正邏輯執(zhí)行前將 threadlocalCopy 賦值給當(dāng)前執(zhí)行線程的上下文,且保存當(dāng)前線程之前的上下文,在執(zhí)行完畢之后,再?gòu)?fù)原此線程的上下文。

4.由于需要在構(gòu)造的時(shí)候復(fù)制所有父線程用到的 YesThreadLocal ,因此需要有個(gè) holder 變量來(lái)保存所有用到的 YesThreadLocal ,這樣在構(gòu)造的時(shí)候才好遍歷賦值。

5.并且 holder 變量也需要線程隔離,所以用 ThreadLocal 修飾,并且為了防止 holder 強(qiáng)引用導(dǎo)致內(nèi)存泄漏,所以用 WeakHashMap 存儲(chǔ)。

6.往 holder 添加 YesThreadLocal 的時(shí)機(jī)就在 YesThreadLocal#set 之時(shí)

TransmittableThreadLocal 的實(shí)現(xiàn)

這篇只講 TTL 核心思想(關(guān)鍵路徑),由于篇幅原因其它的不作展開(kāi),之后再寫一篇詳細(xì)的。

我上面的實(shí)現(xiàn)其實(shí)就是 TTL 的復(fù)制版,如果你理解了上面的實(shí)現(xiàn),那么接下來(lái)對(duì) TTL 介紹理解起來(lái)應(yīng)該很簡(jiǎn)單,相當(dāng)于復(fù)習(xí)了。

我們先簡(jiǎn)單看一下 TTL 的使用方式。

1462b3a8-5cd6-11ee-939d-92fbcf53809c.png

使用起來(lái)很簡(jiǎn)單對(duì)吧?

TTL 對(duì)標(biāo)上面的 YesThreadLocal ,差別在于它繼承的是 InheritableThreadLocal,因?yàn)檫@樣直接 new TTL 也會(huì)擁有父子線程本地變量的傳遞能力。

1483e7c6-5cd6-11ee-939d-92fbcf53809c.png

我們?cè)賮?lái)看看 TTL 的 get 和 set 這兩個(gè)核心操作:

14934dce-5cd6-11ee-939d-92fbcf53809c.png

可以看到 get 和 set 其實(shí)就是復(fù)用父類 ThreadLocal 的方法,關(guān)鍵就在于 addThisToHolder,就是我上面分析的將當(dāng)前使用的 TTL 對(duì)象加到 holder 里面。

14aac10c-5cd6-11ee-939d-92fbcf53809c.png

所以,在父線程賦值即執(zhí)行 set 操作之后,父線程里的 holder 就存儲(chǔ)了當(dāng)前的 TTL 對(duì)象了,即上面演示代碼的 ttl.set() 操作。

然后重點(diǎn)就移到了TtlRunnable.get 上了,根據(jù)上面的理解我們知道這里是要進(jìn)行一個(gè)裝飾的操作,這個(gè) get 代碼也比較簡(jiǎn)單,核心就是 new 一個(gè) TtlRunnable 包裝了原始的 task。

14ba6120-5cd6-11ee-939d-92fbcf53809c.png

那我們來(lái)看一下它的構(gòu)造方法:

14cc5c68-5cd6-11ee-939d-92fbcf53809c.png

這個(gè) capturedRef 其實(shí)就是父線程本地變量的拷貝,然后 capture() 其實(shí)就等同于copyFatherThreadlocal()

再來(lái)看一下 TtlRunnable 裝飾的 run 方法:

14e6099c-5cd6-11ee-939d-92fbcf53809c.png

邏輯很清晰的四步驟:

  1. 拿到父類本地變量拷貝
  2. 賦值給當(dāng)前線程(線程池內(nèi)的某線程),并保存之前的本地變量
  3. 執(zhí)行邏輯
  4. 復(fù)原當(dāng)前線程之前的本地變量

我們?cè)賮?lái)分析一下 capture() 方法,即如何拷貝的。

在 TTL 中是專門定義了一個(gè)靜態(tài)工具類 Transmitter 來(lái)實(shí)現(xiàn)上面的 capture、 replay、restore 操作。

1502c258-5cd6-11ee-939d-92fbcf53809c.png

可以看到 capture 的邏輯其實(shí)就是返回一個(gè)快照,而這個(gè)快照就是遍歷 holder 獲取所有存儲(chǔ)在 holder 里面的 TTL ,返回一個(gè)新的 map,還是很簡(jiǎn)單的吧!

這里還有個(gè) captureThreadLocalValues ,這個(gè)是為兼容那些無(wú)法將 ThreadLocal 類變更至 TTL ,但是又想復(fù)制傳遞 ThreadLocal 的值而使用的,可以先忽略。

我們?cè)賮?lái)看看 replay,即如何將父類的本地變量賦值給當(dāng)前線程的。

1519692c-5cd6-11ee-939d-92fbcf53809c.png

邏輯還是很清晰的,先備份,再拷貝覆蓋,最后會(huì)返回備份,拷貝覆蓋的代碼 setTtlValuesTo 很簡(jiǎn)單:

152bc84c-5cd6-11ee-939d-92fbcf53809c.png

就是 for 循環(huán)進(jìn)行了一波 set ,從這里也可以得知為什么上面需要移除父線程沒(méi)有的 TTL,因?yàn)檫@里只是進(jìn)行了 set。如果不 remove 當(dāng)前線程的本地變量,那就不是完全繼承自父線程的本地變量了,可能摻雜著之前的本地變量,也就是不干凈了,防止這種干擾,所以還是 remove 了為妙。

最后我們看下 restore 操作:

153fc5a4-5cd6-11ee-939d-92fbcf53809c.png

至此想必對(duì) TTL 的原理應(yīng)該都很清晰了吧!

一些用法

上面我們展示的只是其中一個(gè)用法也就是利用 TtlRunnable.get 來(lái)包裝 Runnable。

TTL 還提供了線程池的修飾方法,即 TtlExecutors,比如可以這樣使用:

ExecutorServiceexecutorService=TtlExecutors.getTtlExecutorService(Executors.newFixedThreadPool(1));

其實(shí)原理也很簡(jiǎn)單,裝飾了一下線程池提交任務(wù)的方法,里面實(shí)現(xiàn)了 TtlRunnable.get 的包裝

155e56c2-5cd6-11ee-939d-92fbcf53809c.png

還有一種使用方式更加透明,即利用 Java Agent 來(lái)修飾 JDK 的線程池實(shí)現(xiàn)類,這種方式在使用上基本就是無(wú)感知了。

在 Java 的啟動(dòng)參數(shù)加上:-javaagent:path/to/transmittable-thread-local-2.x.y.jar 即可,然后就正常的使用就行,原生的線程池實(shí)現(xiàn)類已經(jīng)悄悄的被改了!

TransmittableThreadLocalttl=newTransmittableThreadLocal<>();
ExecutorServiceexecutorService=Executors.newFixedThreadPool(1);
Runnabletask=newRunnableTask();
executorService.submit(task);

最后

好了,有關(guān) TTL 的原理和用法解釋的都差不多了。

總結(jié)下來(lái)的核心操作就是 CRR(Capture/Replay/Restore),拷貝快照、重放快照、復(fù)原上下文。

可能有些人會(huì)疑惑為什么需要復(fù)原,線程池的線程每次執(zhí)行的時(shí)候,如果用了 TTL 那執(zhí)行的線程都會(huì)被覆蓋上下文,沒(méi)必要復(fù)原對(duì)吧?

其實(shí)也有人向作者提了這個(gè)疑問(wèn),回答是:

  • 線程池滿了且線程池拒絕策略使用的是『CallerRunsPolicy』,這樣執(zhí)行的線程就變成當(dāng)前線程了,那肯定是要復(fù)原的,不然上下文就沒(méi)了。
  • 使用ForkJoinPool(包含并行執(zhí)行Stream與CompletableFuture,底層使用ForkJoinPool)的場(chǎng)景,展開(kāi)的ForkJoinTask會(huì)在調(diào)用線程中直接執(zhí)行。

其實(shí)關(guān)于 TTL 還有很多細(xì)節(jié)可以說(shuō),不過(guò)篇幅有限,細(xì)節(jié)要說(shuō)的話得再開(kāi)一章。不過(guò)今天這篇也算把 TTL 的核心思想講完了。

假設(shè)現(xiàn)在有個(gè)面試官問(wèn)你,我要向線程池里面?zhèn)鬟f ThreadLocal 怎么實(shí)現(xiàn)呀?想必你肯定可以回答出來(lái)了~


聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 數(shù)據(jù)
    +關(guān)注

    關(guān)注

    8

    文章

    6812

    瀏覽量

    88743
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4722

    瀏覽量

    68236
  • 線程
    +關(guān)注

    關(guān)注

    0

    文章

    503

    瀏覽量

    19636

原文標(biāo)題:ThreadLocal的短板,我TTL來(lái)補(bǔ)!

文章出處:【微信號(hào):芋道源碼,微信公眾號(hào):芋道源碼】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    ThreadLocal實(shí)例應(yīng)用

    ThreadLocal相信大家都用過(guò),但你知道他的原理嗎,今天了不起帶大家學(xué)習(xí)ThreadLocal。 ThreadLocal是什么 在多線程編程中,經(jīng)常會(huì)遇到需要在不同線程中共享數(shù)據(jù)的情況
    的頭像 發(fā)表于 09-30 10:19 ?631次閱讀
    <b class='flag-5'>ThreadLocal</b>實(shí)例應(yīng)用

    ThreadLocal的定義、用法及優(yōu)點(diǎn)

    ThreadLocal 簡(jiǎn)介 ThreadLocal是Java中一個(gè)非常重要的線程技術(shù)。它可以讓每個(gè)線程都擁有自己的變量副本,避免了線程間的競(jìng)爭(zhēng)和數(shù)據(jù)泄露問(wèn)題。在本文中,我們將詳細(xì)介紹
    的頭像 發(fā)表于 09-30 10:14 ?976次閱讀
    <b class='flag-5'>ThreadLocal</b>的定義、用法及優(yōu)點(diǎn)

    二維插補(bǔ)

    主要任務(wù):以單片機(jī)為控制器,步進(jìn)電機(jī)為執(zhí)行器,構(gòu)建一個(gè)二維插補(bǔ)系統(tǒng),該系統(tǒng)能夠進(jìn)行4個(gè)象限的直線、圓弧插補(bǔ)。目標(biāo):設(shè)計(jì)控制系統(tǒng)硬件電路,編寫插補(bǔ)軟件各種插補(bǔ)功能通過(guò)按鍵
    發(fā)表于 02-08 15:47

    補(bǔ)晶振:專家詳解溫補(bǔ)晶振

      你對(duì)溫補(bǔ)晶振了解嗎?或者說(shuō)你了解溫補(bǔ)晶振多少呢?下面我們跟著松季晶振來(lái)全面具體的了解溫補(bǔ)晶振。  1、松季電子介紹說(shuō):溫補(bǔ)晶振即溫度補(bǔ)償
    發(fā)表于 08-14 16:03

    LVDS與TTL轉(zhuǎn)換

    電路中實(shí)現(xiàn)的是28路TTL轉(zhuǎn)為L(zhǎng)VDS,再轉(zhuǎn)為28路TTL,的管腳分配是根據(jù)cameralink的協(xié)議來(lái)的,檢查后也沒(méi)發(fā)現(xiàn)問(wèn)題,下面圖里
    發(fā)表于 08-04 22:40

    需要什么來(lái)適應(yīng)TTL電平到電力線?

    你好,高興地發(fā)現(xiàn),PSoC1(CY8C29)現(xiàn)在能夠“房子”PLC IP解決方案。在我看來(lái),這是一個(gè)非常有趣的問(wèn)題,即使它是一個(gè)資源匱乏的解決方案。的問(wèn)題是…需要什么來(lái)適應(yīng)TTL
    發(fā)表于 05-15 08:36

    補(bǔ)光燈的單片機(jī)開(kāi)發(fā)設(shè)計(jì)

    景完全可以,只要您覺(jué)得昏暗的場(chǎng)景可以用它們來(lái)補(bǔ)光,關(guān)鍵同樣便宜,可以說(shuō)它是日常攝影照明的理想合作伙伴!補(bǔ)光燈有多種類型,包括環(huán)形,方形,桿形等等多種樣式!閃光燈:常見(jiàn)的閃光燈類型是機(jī)器頂部的熱靴閃光燈。當(dāng)然
    發(fā)表于 06-29 18:00

    改進(jìn)型TTL門電路—抗飽和TTL電路

    改進(jìn)型TTL門電路——抗飽和TTL電路   抗飽和TTL電路是目前傳輸速度較高的一類TTL電路。這種電路由于采用肖特基勢(shì)壘二極管SBD鉗位方法來(lái)
    發(fā)表于 04-07 00:16 ?2657次閱讀
    改進(jìn)型<b class='flag-5'>TTL</b>門電路—抗飽和<b class='flag-5'>TTL</b>電路

    補(bǔ)終端短板 TD-SCDMA醞釀商用化質(zhì)變

    補(bǔ)終端短板TD醞釀商用化質(zhì)變    “終端還是現(xiàn)在最令人牽掛的部分?!毙畔a(chǎn)業(yè)部電信研究院一高層對(duì)《第一財(cái)經(jīng)日?qǐng)?bào)》表示,TD-SCDMA網(wǎng)絡(luò)問(wèn)題不大,而終端的成熟度、品
    發(fā)表于 06-23 09:21 ?259次閱讀

    什么是短板印刷

    什么是短板印刷 短板印刷圖片 短板印刷是
    發(fā)表于 10-13 09:29 ?2860次閱讀

    ThreadLocal發(fā)生內(nèi)存泄漏的原因

    ,就可能會(huì)導(dǎo)致內(nèi)存泄漏。下面,我們將圍繞三個(gè)方面來(lái)分析 ThreadLocal 內(nèi)存泄漏的問(wèn)題 ThreadLocal 實(shí)現(xiàn)原理 ThreadLocal為什么會(huì)內(nèi)存泄漏
    的頭像 發(fā)表于 05-05 16:23 ?3650次閱讀

    如何使用ThreadLocal來(lái)避免內(nèi)存泄漏

    本次給大家介紹重要的工具ThreadLocal。講解內(nèi)容如下,同時(shí)介紹什么場(chǎng)景下發(fā)生內(nèi)存泄漏,如何復(fù)現(xiàn)內(nèi)存泄漏,如何正確使用它來(lái)避免內(nèi)存泄漏。 ThreadLocal是什么?有哪些用途
    的頭像 發(fā)表于 08-20 09:29 ?4190次閱讀
    如何使用<b class='flag-5'>ThreadLocal</b><b class='flag-5'>來(lái)</b>避免內(nèi)存泄漏

    ThreadLocal源碼解析及實(shí)戰(zhàn)應(yīng)用

    ThreadLocal 是一個(gè)關(guān)于創(chuàng)建線程局部變量的類。
    的頭像 發(fā)表于 01-29 14:53 ?443次閱讀

    ThreadLocal基本內(nèi)容與用法

    下面我們就來(lái)看看道哥都用的ThreadLocal。 1 ThreadLocal你來(lái)自哪里 Since : 1.2 Author : Josh Bloch and Doug Lea 又是并發(fā)大佬們
    的頭像 發(fā)表于 10-13 11:39 ?425次閱讀

    無(wú)功補(bǔ)償?shù)墓?b class='flag-5'>補(bǔ)、分補(bǔ)、混補(bǔ)

    的穩(wěn)定性和可靠性。 在實(shí)際應(yīng)用中,無(wú)功補(bǔ)償主要分為共補(bǔ)、分補(bǔ)和混補(bǔ)三種方式。 共補(bǔ)是指在電力系統(tǒng)中通過(guò)集中式的無(wú)功補(bǔ)償設(shè)備來(lái)補(bǔ)償整個(gè)系統(tǒng)的無(wú)
    的頭像 發(fā)表于 12-19 15:47 ?799次閱讀