国产精品久久久aaaa,日日干夜夜操天天插,亚洲乱熟女香蕉一区二区三区少妇,99精品国产高清一区二区三区,国产成人精品一区二区色戒,久久久国产精品成人免费,亚洲精品毛片久久久久,99久久婷婷国产综合精品电影,国产一区二区三区任你鲁

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

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

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

讀懂HikariCP一百行代碼,多線程就是個(gè)孫子!

jf_ro2CN3Fa ? 來(lái)源:芋道源碼 ? 作者:芋道源碼 ? 2022-12-14 15:45 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群


總結(jié):Java屆很難得有讀百十行代碼就能增加修煉的機(jī)會(huì),這里有一個(gè)。

通常,我在看書的時(shí)候一般不寫代碼,因?yàn)槲业哪X袋被設(shè)定成單線程的,一旦同時(shí)喂給它不同的信息,它就無(wú)法處理。

但多線程對(duì)電腦來(lái)說(shuō)就是小菜一碟,它可以同時(shí)做很多事,看起來(lái)匪夷所思。好希望把自己的大腦皮層移植到這些牛x的設(shè)備上。

用人腦思考電腦正在思考的問(wèn)題,這本身就是一種折磨。但平常的工作和面試中,又不得不面對(duì)這樣的場(chǎng)景,所以多線程就成了編程路上一塊難啃的骨頭。

HikariCP是SpringBoot默認(rèn)的數(shù)據(jù)庫(kù)連接池,它毫不謙虛的的起了一個(gè)叫做的名字,這讓國(guó)產(chǎn)Druid很沒(méi)面子。

還是言歸正傳,看一下Hikari中的ConcurrentBag吧。

核心數(shù)據(jù)結(jié)構(gòu)

多線程代碼一個(gè)讓人比較頭疼的問(wèn)題,就是每個(gè)API我都懂,但就是不會(huì)用。很多對(duì)concurrent包倒背如流的同學(xué),在面對(duì)現(xiàn)實(shí)的問(wèn)題時(shí),到最后依然不得不被迫加上Lock或者synchronized。

ConcurrentBag是一個(gè)Lock free的數(shù)據(jù)結(jié)構(gòu),主要用作數(shù)據(jù)庫(kù)連接的存儲(chǔ),可以說(shuō)整個(gè)HikariCP的核心就是它。刪掉亂七八糟的注釋和異常處理,可以說(shuō)關(guān)鍵的代碼也就百十來(lái)行,但里面的道道卻非常的多。

ConcurrentBag速度很快,要達(dá)到這個(gè)目標(biāo),就需要一定的核心數(shù)據(jù)結(jié)構(gòu)支持。

privatefinalCopyOnWriteArrayListsharedList;
privatefinalThreadLocal>threadList;
privatefinalAtomicIntegerwaiters;
privatefinalSynchronousQueuehandoffQueue;
  • sharedList 用來(lái)緩存所有的連接,是一個(gè)CopyOnWriteArrayList結(jié)構(gòu)。
  • threadList 用來(lái)緩存某個(gè)線程所使用的所有連接,相當(dāng)于快速引用,是一個(gè)ThreadLocal類型的ArrayList。
  • waiters 當(dāng)前正在獲取連接的等待者數(shù)量。AtomicInteger,就是一個(gè)自增對(duì)象。當(dāng)waiters的數(shù)量大于0時(shí)候,意味著有線程正在獲取資源。
  • handoffQueue 0容量的快速傳遞隊(duì)列,SynchronousQueue類型的隊(duì)列,非常有用。

ConcurrentBag里面的元素,為了能夠無(wú)鎖化操作,需要使用一些變量來(lái)標(biāo)識(shí)現(xiàn)在處于的狀態(tài)。抽象的接口如下:

publicinterfaceIConcurrentBagEntry{
intSTATE_NOT_IN_USE=0;
intSTATE_IN_USE=1;
intSTATE_REMOVED=-1;
intSTATE_RESERVED=-2;

booleancompareAndSet(intexpectState,intnewState);
voidsetState(intnewState);
intgetState();
}

有了這些數(shù)據(jù)結(jié)構(gòu)的支持,我們的ConcurrentBag就可以實(shí)現(xiàn)它光的宣稱了。

基于 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/

獲取連接

連接的獲取是borrow方法,還可以傳入一個(gè)timeout作為超時(shí)控制。

publicTborrow(longtimeout,finalTimeUnittimeUnit)throwsInterruptedException

首先,如果某個(gè)線程執(zhí)行非常快,使用了比較多的連接,就可以使用ThreadLocal的方式快速獲取連接對(duì)象,而不用跑到大池子里面去獲取。代碼如下。

//Trythethread-locallistfirst
finalvarlist=threadList.get();
for(inti=list.size()-1;i>=0;i--){
finalvarentry=list.remove(i);
finalTbagEntry=weakThreadLocals?((WeakReference)entry).get():(T)entry;
if(bagEntry!=null&&bagEntry.compareAndSet(STATE_NOT_IN_USE,STATE_IN_USE)){
returnbagEntry;
}
}

我們都知道,包括ArrayList和HashMap一些基礎(chǔ)的結(jié)構(gòu),都是Fail Fast的,如果你在遍歷的時(shí)候,刪掉一些數(shù)據(jù),有可能會(huì)引起問(wèn)題。幸運(yùn)的是,由于我們的List是從ThreadLocal獲取的,它首先就避免了線程安全的問(wèn)題。

接下來(lái)就是遍歷。這段代碼采用的是尾遍歷(頭遍歷會(huì)出現(xiàn)錯(cuò)誤),用于快速的從列表中找到一個(gè)可以復(fù)用的對(duì)象,然后使用CAS來(lái)把狀態(tài)置為使用中。但如果對(duì)象正在被使用,則直接刪除它。

在ConcurrentBag里,每個(gè)ThreadLocal最多緩存50個(gè)連接對(duì)象引用。

當(dāng)ThreadLocal里找不到可復(fù)用的對(duì)象,它就會(huì)到大池子里去拿。也就是下面這段代碼。

//Otherwise,scanthesharedlist...thenpollthehandoffqueue
finalintwaiting=waiters.incrementAndGet();
try{
for(TbagEntry:sharedList){
if(bagEntry.compareAndSet(STATE_NOT_IN_USE,STATE_IN_USE)){
//Ifwemayhavestolenanotherwaiter'sconnection,requestanotherbagadd.
if(waiting>1){
listener.addBagItem(waiting-1);
}
returnbagEntry;
}
}

listener.addBagItem(waiting);

//還拿不到,就需要等待別人釋放了
timeout=timeUnit.toNanos(timeout);
do{
finalvarstart=currentTime();
finalTbagEntry=handoffQueue.poll(timeout,NANOSECONDS);
if(bagEntry==null||bagEntry.compareAndSet(STATE_NOT_IN_USE,STATE_IN_USE)){
returnbagEntry;
}

timeout-=elapsedNanos(start);
}while(timeout>10_000);

returnnull;
}
finally{
waiters.decrementAndGet();
}

首先要注意,這段代碼可能是由不同的線程執(zhí)行的,所以必須要考慮線程安全問(wèn)題。由于shardList是線程安全的CopyOnWriteArrayList,適合讀多寫少的場(chǎng)景,我們可以直接進(jìn)行遍歷。

這段代碼的目的是一樣的,需要從sharedList找到一個(gè)空閑的連接對(duì)象。這里把自增的waiting變量傳遞到外面的代碼進(jìn)行處理,主要是由于想要根據(jù)waiting的大小來(lái)確定是否創(chuàng)建新的對(duì)象。

如果無(wú)法從池子里獲取連接,則需要等待別的線程釋放一些資源。

創(chuàng)建對(duì)象的過(guò)程是異步的,要想獲取它,還需要依賴一段循環(huán)代碼。while循環(huán)代碼是納秒精度,會(huì)嘗試從handoffQueue里獲取。最終會(huì)調(diào)用SynchronousQueue的transfer方法。

基于 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/

歸還連接

有借就有還,當(dāng)某個(gè)連接使用完畢,它將被歸還到池子中。

publicvoidrequite(finalTbagEntry)
{
bagEntry.setState(STATE_NOT_IN_USE);

for(vari=0;waiters.get()>0;i++){
if(bagEntry.getState()!=STATE_NOT_IN_USE||handoffQueue.offer(bagEntry)){
return;
}
elseif((i&0xff)==0xff){
parkNanos(MICROSECONDS.toNanos(10));
}
else{
Thread.yield();
}
}

finalvarthreadLocalList=threadList.get();
if(threadLocalList.size()50){
threadLocalList.add(weakThreadLocals?newWeakReference<>(bagEntry):bagEntry);
}
}

首先,把這個(gè)對(duì)象置為可用狀態(tài)。然后,代碼會(huì)進(jìn)入一個(gè)循環(huán),等待使用方把這個(gè)連接接手過(guò)去。當(dāng)連接處于STATE_NOT_IN_USE狀態(tài),或者隊(duì)列中的數(shù)據(jù)被取走了,那么就可以直接返回了。

由于waiters.get()是實(shí)時(shí)獲取的,有可能長(zhǎng)時(shí)間一直大于0,這樣代碼就會(huì)變成死循環(huán),浪費(fèi)CPU。代碼會(huì)嘗試不同層次的睡眠,一個(gè)是每隔255個(gè)waiter睡10ns,一個(gè)是使用yield讓出cpu時(shí)間片。

如果歸還連接的時(shí)候并沒(méi)有被其他線程獲取到,那么最后我們會(huì)把歸還的連接放入到相對(duì)應(yīng)的ThreadLocal里,因?yàn)閷?duì)一個(gè)連接來(lái)說(shuō),借和還,通常是一個(gè)線程。

知識(shí)點(diǎn)

看起來(lái)平平無(wú)奇的幾行代碼,為什么搞懂了就能Hold住大部分的并發(fā)編程場(chǎng)景呢?主要還是這里面的知識(shí)點(diǎn)太多。下面我簡(jiǎn)單羅列一下,你可以逐個(gè)攻破。

  1. 使用ThreadLocal來(lái)緩存本地資源引用,使用線程封閉的資源來(lái)減少鎖的沖突
  2. 采用讀多寫少的線程安全的CopyOnWriteArrayList來(lái)緩存所有對(duì)象,幾乎不影響讀取效率
  3. 使用基于CAS的AtomicInteger來(lái)計(jì)算等待者的數(shù)量,無(wú)鎖操作使得計(jì)算更加快速
  4. 0容量的交換隊(duì)列SynchronousQueue,使得對(duì)象傳遞更加迅速
  5. 采用compareAndSet的CAS原語(yǔ)來(lái)控制狀態(tài)的變更,安全且效率高。很多核心代碼都是這么設(shè)計(jì)的
  6. 在循環(huán)中使用park、yield等方法,避免死循環(huán)占用大量CPU
  7. 需要了解并發(fā)數(shù)據(jù)結(jié)構(gòu)中的offer、poll、peek、put、take、add、remove方法的區(qū)別,并靈活應(yīng)用
  8. CAS在設(shè)置狀態(tài)時(shí),采用了volatile關(guān)鍵字修飾,對(duì)于volatile的使用也是一個(gè)常見(jiàn)的優(yōu)化點(diǎn)
  9. 需要了解WeakReference弱引用在垃圾回收時(shí)候的表現(xiàn)

麻雀雖小,五臟俱全。如果你想要你的多線程編程能力更上一層樓,讀一讀這個(gè)短小精悍的ConcurrentBag吧。當(dāng)你掌握了它,多線程的那些東西,不過(guò)是小菜一碟。

審核編輯 :李倩


聲明:本文內(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)投訴
  • cpu
    cpu
    +關(guān)注

    關(guān)注

    68

    文章

    11279

    瀏覽量

    225018
  • 數(shù)據(jù)庫(kù)
    +關(guān)注

    關(guān)注

    7

    文章

    4020

    瀏覽量

    68355
  • 多線程
    +關(guān)注

    關(guān)注

    0

    文章

    279

    瀏覽量

    21033

原文標(biāo)題:讀懂HikariCP一百行代碼,多線程就是個(gè)孫子!

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

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    小馬智與摩爾線程達(dá)成戰(zhàn)略合作

    2月6日,小馬智與國(guó)產(chǎn)全功能GPU領(lǐng)軍企業(yè)摩爾線程正式宣布達(dá)成戰(zhàn)略合作。雙方將聚焦L4級(jí)自動(dòng)駕駛技術(shù)落地與規(guī)模化應(yīng)用,圍繞小馬智的技術(shù)核心——世界模型及虛擬司機(jī)系統(tǒng)的訓(xùn)練與優(yōu)化展開(kāi)深度協(xié)同,以安全可靠的AI算力,賦能自動(dòng)駕駛
    的頭像 發(fā)表于 02-06 09:23 ?3611次閱讀

    【瑞薩RA × Zephyr評(píng)測(cè)】多線程和看門狗

    本文章旨在評(píng)估使用 Zephyr RTOS 在 Renesas FPB-RA6E2 開(kāi)發(fā)板上實(shí)現(xiàn)多線程調(diào)度與硬件看門狗功能的應(yīng)用。評(píng)估內(nèi)容包括任務(wù)調(diào)度、看門狗初始化流程、主程序邏輯的詳細(xì)解析,以及實(shí)驗(yàn)現(xiàn)象與數(shù)據(jù)分析。
    的頭像 發(fā)表于 01-10 10:23 ?2475次閱讀
    【瑞薩RA × Zephyr評(píng)測(cè)】<b class='flag-5'>多線程</b>和看門狗

    解析Linux的進(jìn)程、線程和協(xié)程

    一、基礎(chǔ)概念 進(jìn)程(Process) 進(jìn)程是計(jì)算機(jī)中運(yùn)行的程序的實(shí)例,它是操作系統(tǒng)中最基本的執(zhí)行單元之一。每個(gè)進(jìn)程都有自己的獨(dú)立內(nèi)存空間、系統(tǒng)資源和代碼執(zhí)行流。這意味著一個(gè)進(jìn)程的崩潰通常不會(huì)
    發(fā)表于 12-22 11:00

    多線程的系統(tǒng)

    多線程系統(tǒng)的事件響應(yīng)也是在中斷中完成的,但事件的處理是在線程中完成的。在多線程系統(tǒng)中,線程跟中斷一樣,也具有優(yōu)先級(jí),優(yōu)先級(jí)高的線程會(huì)被優(yōu)先執(zhí)
    發(fā)表于 12-08 07:55

    Linux多線程對(duì)比單線程的優(yōu)勢(shì)

    ,而單線程則需要通過(guò)進(jìn)程間通信來(lái)實(shí)現(xiàn)。「上下文切換開(kāi)銷小」:線程的上下文切換比進(jìn)程小,因?yàn)樗鼈児蚕硐嗤牡刂房臻g。「提高響應(yīng)性」:多線程可以使程序更加響應(yīng)用戶輸入或其他事件,避免阻塞。下面是一
    發(fā)表于 12-01 06:11

    rt-thread studio 如何進(jìn)行多線程編譯?

    ,使用的是5800h+32g內(nèi)存+sn550 ssd,開(kāi)啟16線程編譯時(shí)cpu的占用率也只能到30%,編譯完整個(gè)工程需要3分鐘 感覺(jué)多線程編譯設(shè)置沒(méi)有生效,有辦法提高編譯速度嗎 rtthread studio版本是 2.2.9
    發(fā)表于 10-11 09:16

    tcpip線程被mu0鎖住導(dǎo)致網(wǎng)絡(luò)線程無(wú)法使用怎么解決?

    和RS485接收發(fā)送線程沒(méi)死,我在程序里添加了一個(gè)接收指定字符后,打印一些函數(shù)結(jié)果的代碼代碼如下: ch = uart_sample_get_char(); // LOG_D(\"
    發(fā)表于 09-29 06:41

    啟用了控制臺(tái)后,空閑線程是不是永遠(yuǎn)不會(huì)進(jìn)入?

    在控制臺(tái)里打印線程(list thread)時(shí),發(fā)現(xiàn)已經(jīng)退出的線程已經(jīng)是CLOSE狀態(tài),但是都是僵尸線程。然后查看shell代碼,看到控制臺(tái)一直在跑,所以手動(dòng)添加了延時(shí)(rt_thre
    發(fā)表于 09-19 06:53

    【HZ-T536開(kāi)發(fā)板免費(fèi)體驗(yàn)】—— linux創(chuàng)建線程

    自己的私有資源。 在linux系統(tǒng)中,線程狀態(tài)通常反映了當(dāng)前線程的當(dāng)前活動(dòng)和執(zhí)行階段。 主要分為: 1。運(yùn)行轉(zhuǎn)態(tài) 2。阻塞轉(zhuǎn)態(tài) 3。終止?fàn)顟B(tài) 如何區(qū)分單線程多線程? 在單個(gè)程序中只
    發(fā)表于 09-01 21:31

    【RA4E2開(kāi)發(fā)板評(píng)測(cè)】LED1及LED2輪流點(diǎn)亮并同時(shí)亮8秒,體驗(yàn)FreeRTOS多線程

    線程 -- 在頁(yè)面下方的屬性里Support Dynamic Allocation 改為 Enabled。見(jiàn)下圖。 保存配置文件,點(diǎn)擊生成項(xiàng)目代碼。 4 編寫多線程FreeRTOS代碼
    發(fā)表于 08-24 17:24

    多線程的安全注意事項(xiàng)

    多線程安全是指多個(gè)線程同時(shí)訪問(wèn)或修改共享資源時(shí),能夠保證程序的正確性和可靠性。 開(kāi)發(fā)者選擇TaskPool或Worker進(jìn)行多線程開(kāi)發(fā)時(shí),在TaskPool和Worker的工作線程中導(dǎo)
    發(fā)表于 06-20 07:49

    工控一體機(jī)多線程任務(wù)調(diào)度優(yōu)化:聚徽分享破解工業(yè)復(fù)雜流程高效協(xié)同密碼

    在當(dāng)今工業(yè) 4.0 的浪潮下,工業(yè)生產(chǎn)正朝著高度自動(dòng)化、智能化的方向大步邁進(jìn)。生產(chǎn)流程日益復(fù)雜,眾多任務(wù)需要同時(shí)、高效地協(xié)同執(zhí)行,這對(duì)工業(yè)控制系統(tǒng)的核心 —— 工控一體機(jī)提出了前所未有的挑戰(zhàn)。多線程
    的頭像 發(fā)表于 05-28 14:06 ?639次閱讀

    一種實(shí)時(shí)多線程VSLAM框架vS-Graphs介紹

    針對(duì)現(xiàn)有VSLAM系統(tǒng)語(yǔ)義表達(dá)不足、地圖可解釋性差的問(wèn)題,本文提出vS-Graphs,一種實(shí)時(shí)多線程VSLAM框架。該方案顯著提升了重建地圖的語(yǔ)義豐富度、可解釋性及定位精度。實(shí)驗(yàn)表明
    的頭像 發(fā)表于 04-19 14:07 ?1009次閱讀
    一種實(shí)時(shí)<b class='flag-5'>多線程</b>VSLAM框架vS-Graphs介紹

    進(jìn)程、線程、協(xié)程傻傻分不清?一文帶你徹底扒光它們的\"底褲\"!

    外賣員(線程C):負(fù)責(zé)送外賣他們共用: 原料冰箱(共享內(nèi)存) 工作臺(tái)(棧空間)但不共享: 自己的工牌(線程ID) 心情日記(線程本地存儲(chǔ)) 代碼示例(Python
    發(fā)表于 03-26 09:27

    請(qǐng)問(wèn)如何在Python中實(shí)現(xiàn)多線程與多進(jìn)程的協(xié)作?

    大家好!我最近在開(kāi)發(fā)一個(gè)Python項(xiàng)目時(shí),需要同時(shí)處理多個(gè)任務(wù),且每個(gè)任務(wù)需要不同的計(jì)算資源。我想通過(guò)多線程和多進(jìn)程的組合來(lái)實(shí)現(xiàn)并發(fā),但遇到了一些問(wèn)題。 具體來(lái)說(shuō),我有兩個(gè)任務(wù),一個(gè)
    發(fā)表于 03-11 06:57