<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      符合死鎖的四個(gè)條件:

      1. 互斥條件:一個(gè)時(shí)刻一個(gè)線(xiàn)程一個(gè)資源

      2. 請(qǐng)求與保持條件:一個(gè)線(xiàn)程因請(qǐng)求資源而阻塞時(shí),對(duì)已獲得的資源保持不放。

      3. 不剝奪條件:線(xiàn)程已獲得的資源,在未用完之前,不能被其他線(xiàn)程剝奪。

      4. 循環(huán)等待條件:若干線(xiàn)程形成頭尾相接的循環(huán)等待資源關(guān)系。

      如何預(yù)防和避免線(xiàn)程死鎖:

      1. 破壞請(qǐng)求與保持條件:一次性申請(qǐng)所有資源
      2. 破壞不剝奪條件:占用部分資源的線(xiàn)程進(jìn)一步申請(qǐng)其他資源時(shí),如果申請(qǐng)不到,可以主動(dòng)釋放它占有的資源。
      3. 靠按序申請(qǐng)資源來(lái)預(yù)防。按某一順序申請(qǐng)資源,釋放資源則反序釋放。破壞循環(huán)等待條件。

      避免死鎖:

      ? 避免死鎖就是在資源分配時(shí),借助于算法(比如銀行家算法)對(duì)資源分配進(jìn)行計(jì)算評(píng)估,使其進(jìn)入安全狀態(tài)

      ? 安全狀態(tài):指的是系統(tǒng)能夠按照某種線(xiàn)程推進(jìn)順序(P1,P2,P3...Pn)來(lái)為每個(gè)線(xiàn)程分配資源。知道每個(gè)線(xiàn)程對(duì)資源的最大需求,是每個(gè)線(xiàn)程都iiu可以順利完成。稱(chēng)< P1,P2...Pn>序列為安全序列。

      sleep()方法沒(méi)有釋放鎖,wait()方法釋放了鎖。

      可以直接調(diào)用Thread類(lèi)的run方法:

      ? 調(diào)用 start() 方法方可啟動(dòng)線(xiàn)程并使線(xiàn)程進(jìn)入就緒狀態(tài),直接執(zhí)行 run() 方法的話(huà)不會(huì)以多線(xiàn)程的方式執(zhí)行。

      ? run方法可以創(chuàng)建一個(gè)線(xiàn)程,但是相當(dāng)于同步的方式,沒(méi)有多線(xiàn)程的存在。

      只有調(diào)用start方法才是交給jvm管理,才是多線(xiàn)程。

      為什么需要內(nèi)存模型JMM(Java Memory Model)

      ? 一般來(lái)說(shuō),編程語(yǔ)言也可以直接復(fù)用操作系統(tǒng)層面的內(nèi)存模型。不過(guò),不同的操作系統(tǒng)內(nèi)存模型不同。如果直接復(fù)用操作系統(tǒng)層面的內(nèi)存模型,就可能會(huì)導(dǎo)致同樣一套代碼換了一個(gè)操作系統(tǒng)就無(wú)法執(zhí)行了。Java 語(yǔ)言是跨平臺(tái)的,它需要自己提供一套內(nèi)存模型以屏蔽系統(tǒng)差異。

      ? 這只是 JMM 存在的其中一個(gè)原因。實(shí)際上,對(duì)于 Java 來(lái)說(shuō),你可以把 JMM 看作是 Java 定義的并發(fā)編程相關(guān)的一組規(guī)范,除了抽象了線(xiàn)程和主內(nèi)存之間的關(guān)系之外,其還規(guī)定了從 Java 源代碼到 CPU 可執(zhí)行指令的這個(gè)轉(zhuǎn)化過(guò)程要遵守哪些和并發(fā)相關(guān)的原則和規(guī)范,其主要目的是為了簡(jiǎn)化多線(xiàn)程編程,增強(qiáng)程序可移植性的。

      ? 簡(jiǎn)化多線(xiàn)程編程和增強(qiáng)程序可移植性的

      happen-before原則

      ? happens-before 原則表達(dá)的意義其實(shí)并不是一個(gè)操作發(fā)生在另外一個(gè)操作的前面,雖然這從程序員的角度上來(lái)說(shuō)也并無(wú)大礙。更準(zhǔn)確地來(lái)說(shuō),它更想表達(dá)的意義是前一個(gè)操作的結(jié)果對(duì)于后一個(gè)操作是可見(jiàn)的,無(wú)論這兩個(gè)操作是否在同一個(gè)線(xiàn)程里。


      volatile 的作用

      1. ? 保證變量的內(nèi)存可見(jiàn)性
      2. ? 禁止指令重排序

      volatile 關(guān)鍵字能保證數(shù)據(jù)的可見(jiàn)性,但不能保證數(shù)據(jù)的原子性synchronized 關(guān)鍵字兩者都能保證。

      樂(lè)觀鎖和悲觀鎖

      悲觀鎖

      ? 像 Java 中synchronizedReentrantLock等獨(dú)占鎖就是悲觀鎖思想的實(shí)現(xiàn)。

      樂(lè)觀鎖

      ? 版本號(hào)機(jī)制和CAS算法。

      CAS算法:

      ? Compare And Swap

      ? 函數(shù)公式:CAS(V,E,N)V:表示要更新的變量E:表示預(yù)期值N:表示新值。

      ? CAS算法詳解 - 知乎 (zhihu.com)

      版本號(hào)機(jī)制:

      image-20230913103827343

      ABA問(wèn)題

      image-20230913104139016

      LongAdder:

      image-20230913103432278

      image-20230913103422314

      樂(lè)觀鎖總結(jié)

      image-20230913105001248

      哈哈總結(jié)

      理論上來(lái)說(shuō):

      • 悲觀鎖通常多用于寫(xiě)比較多的情況下(多寫(xiě)場(chǎng)景,競(jìng)爭(zhēng)激烈),這樣可以避免頻繁失敗和重試影響性能,悲觀鎖的開(kāi)銷(xiāo)是固定的。不過(guò),如果樂(lè)觀鎖解決了頻繁失敗和重試這個(gè)問(wèn)題的話(huà)(比如LongAdder),也是可以考慮使用樂(lè)觀鎖的,要視實(shí)際情況而定。
      • 樂(lè)觀鎖通常多于寫(xiě)比較少的情況下(多讀場(chǎng)景,競(jìng)爭(zhēng)較少),這樣可以避免頻繁加鎖影響性能。不過(guò),樂(lè)觀鎖主要針對(duì)的對(duì)象是單個(gè)共享變量(參考java.util.concurrent.atomic包下面的原子變量類(lèi))

      (AbstractQueuedSynchronizer)

      ? 主要用來(lái)構(gòu)造鎖和同步器。比如:ReentrantLock ,Semaphore。

      AQS核心思想

      • ? AQS 核心思想是,如果被請(qǐng)求的共享資源空閑,則將當(dāng)前請(qǐng)求資源的線(xiàn)程設(shè)置為有效的工作線(xiàn)程,并且將共享資源設(shè)置為鎖定狀態(tài)。如果被請(qǐng)求的共享資源被占用,那么就需要一套線(xiàn)程阻塞等待以及被喚醒時(shí)鎖分配的機(jī)制,這個(gè)機(jī)制 AQS 是基于 CLH 鎖 (Craig, Landin, and Hagersten locks) 實(shí)現(xiàn)的。
      • CLH鎖: 其實(shí)是一個(gè)虛擬的雙向隊(duì)列(虛擬即不存在實(shí)例,僅存在節(jié)點(diǎn)之間的關(guān)聯(lián)關(guān)系)。暫時(shí)獲取不到鎖得線(xiàn)程被加入到該隊(duì)列中。AQS 將每條請(qǐng)求共享資源的線(xiàn)程封裝成一個(gè) CLH 隊(duì)列鎖的一個(gè)結(jié)點(diǎn)(Node)來(lái)實(shí)現(xiàn)鎖的分配。在 CLH 隊(duì)列鎖中,一個(gè)節(jié)點(diǎn)表示一個(gè)線(xiàn)程,它保存著線(xiàn)程的引用(thread)、 當(dāng)前節(jié)點(diǎn)在隊(duì)列中的狀態(tài)(waitStatus)、前驅(qū)節(jié)點(diǎn)(prev)、后繼節(jié)點(diǎn)(next)。
      • AQS使用int成員變量state表示同步狀態(tài),通過(guò)內(nèi)置得FIFO線(xiàn)程等待/等待線(xiàn)程來(lái)完成獲取資源現(xiàn)成的排隊(duì)工作。

      AQS資源共享方式

      • 獨(dú)占Exclusive(只有一個(gè)線(xiàn)程能執(zhí)行,如ReentrantLock)

      • 共享Share(多個(gè)線(xiàn)程可以給同時(shí)執(zhí)行,如Semaphore/CountDownLatch)

      常見(jiàn)同步工具類(lèi)

      Semaphore(信號(hào)量)

      ? synchronizedReentrantLock 都是一次只允許一個(gè)線(xiàn)程訪問(wèn)某個(gè)資源,而Semaphore(信號(hào)量)可以用來(lái)控制同時(shí)訪問(wèn)特定資源的線(xiàn)程數(shù)量

      ? Semaphore 通常用于那些資源有明確訪問(wèn)數(shù)量限制的場(chǎng)景比如限流(僅限于單機(jī)模式,實(shí)際項(xiàng)目中推薦使用 Redis +Lua 來(lái)做限流)。

      原理

      ? Semaphore是共享鎖的一種實(shí)現(xiàn),默認(rèn)構(gòu)造的AQS的state值為permits。

      ? 以無(wú)參 acquire 方法為例,調(diào)用semaphore.acquire() ,線(xiàn)程嘗試獲取許可證,如果 state > 0 的話(huà),則表示可以獲取成功,如果 state <= 0 的話(huà),則表示許可證數(shù)量不足,獲取失敗。

      ? 如果可以獲取成功的話(huà)(state > 0 ),會(huì)嘗試使用 CAS 操作去修改 state 的值 state=state-1。如果獲取失敗則會(huì)創(chuàng)建一個(gè) Node 節(jié)點(diǎn)加入等待隊(duì)列,掛起當(dāng)前線(xiàn)程。

      ?


      ReentrantLock 與synchronized的區(qū)別(增加了那些高級(jí)功能)

      ? 等待可中斷:lock.lockInterruptibly()。synchronized不可中斷。

      ? 可實(shí)現(xiàn)公平鎖。

      ? 可實(shí)現(xiàn)選擇性通知(鎖可以綁定多個(gè)條件) synchronized=>wait(),notify()/notifyAll(),等待通知,ReentrantLocak=>Condtiton。使用notify()/notifyAll()方法進(jìn)行通知時(shí),被通知的線(xiàn)程是由 JVM 選擇的,用ReentrantLock類(lèi)結(jié)合Condition實(shí)例可以實(shí)現(xiàn)選擇性通知使用notify()/notifyAll()方法進(jìn)行通知時(shí),被通知的線(xiàn)程是由 JVM 選擇的,用ReentrantLock類(lèi)結(jié)合Condition實(shí)例可以實(shí)現(xiàn)“選擇性通知”

      ReentrantReadWriteLock

      ? 其實(shí)是兩把鎖:讀鎖(共享鎖(一把鎖可以被多個(gè)線(xiàn)程同時(shí)獲得))和寫(xiě)鎖(獨(dú)占鎖)

      ? 底層也是AQS。

      讀鎖拿到,能不能拿到寫(xiě)鎖(不能);相反分情況。

      ? 在線(xiàn)程持有讀鎖的情況下,該線(xiàn)程不能取得寫(xiě)鎖(因?yàn)楂@取寫(xiě)鎖的時(shí)候,如果發(fā)現(xiàn)當(dāng)前的讀鎖被占用,就馬上獲取失敗,不管讀鎖是不是被當(dāng)前線(xiàn)程持有)。

      ? 在線(xiàn)程持有寫(xiě)鎖的情況下,該線(xiàn)程可以繼續(xù)獲取讀鎖(獲取讀鎖時(shí)如果發(fā)現(xiàn)寫(xiě)鎖被占用,只有寫(xiě)鎖沒(méi)有被當(dāng)前線(xiàn)程占用的情況才會(huì)獲取失敗)

      讀鎖為什么不能升級(jí)為寫(xiě)鎖

      ? 可降級(jí)不可升級(jí)。

      ? 因?yàn)樯?jí)會(huì)導(dǎo)致,引發(fā)線(xiàn)程的爭(zhēng)奪(會(huì)導(dǎo)致死鎖);并且寫(xiě)鎖是獨(dú)占鎖,回影響性能

      StampedLock

      ? jdk1.8引入,讀寫(xiě)鎖;不可重入;不支持條件變量Condition

      ? 不同于一般Lock類(lèi),不是直接實(shí)現(xiàn)Lock或ReadWriteLock接口,基于CLH鎖(AQS也是基于這個(gè))獨(dú)立實(shí)現(xiàn)的。

      三種讀寫(xiě)控制模式:讀鎖,寫(xiě)鎖,樂(lè)觀鎖。

      • 寫(xiě)鎖:獨(dú)占鎖(一把鎖只能被一個(gè)線(xiàn)程獲取)。當(dāng)一個(gè)線(xiàn)程獲取寫(xiě)鎖后,其他請(qǐng)求讀鎖和寫(xiě)鎖的線(xiàn)程必須等待。類(lèi)似于 ReentrantReadWriteLock 的寫(xiě)鎖,不過(guò)這里的寫(xiě)鎖是不可重入的。

      • 讀鎖(悲觀鎖):共享鎖,沒(méi)有線(xiàn)程獲取寫(xiě)鎖的情況下,多個(gè)線(xiàn)程可以同時(shí)持有讀鎖。如果己經(jīng)有線(xiàn)程持有寫(xiě)鎖,則其他線(xiàn)程請(qǐng)求獲取該讀鎖會(huì)被阻塞。類(lèi)似于 ReentrantReadWriteLock 的讀鎖,不過(guò)這里的讀鎖是不可重入的。

      • 樂(lè)觀讀:允許多個(gè)線(xiàn)程獲取樂(lè)觀讀以及讀鎖。同時(shí)允許一個(gè)寫(xiě)線(xiàn)程獲取寫(xiě)鎖。

        StampedLock實(shí)現(xiàn)了不僅多個(gè)讀不互相阻塞,同時(shí)在讀操作時(shí)不會(huì)阻塞寫(xiě)操作能夠達(dá)到這種效果,它的核心思想在于,**在讀的時(shí)候如果發(fā)生了寫(xiě),應(yīng)該通過(guò)重試的方式來(lái)獲取新的值,而不應(yīng)該阻塞寫(xiě)操作。

        這種操作方式?jīng)Q定了StampedLock在讀線(xiàn)程非常多而寫(xiě)線(xiàn)程非常少的場(chǎng)景下非常適用,同時(shí)還避免了寫(xiě)?zhàn)囸I情況的發(fā)生。

        StampedLock不可重入

        tampedLock 在獲取鎖的時(shí)候會(huì)返回一個(gè) long 型的數(shù)據(jù)戳,該數(shù)據(jù)戳用于稍后的鎖釋放參數(shù),如果返回的數(shù)據(jù)戳為 0 則表示鎖獲取失敗。當(dāng)前線(xiàn)程持有了鎖再次獲取鎖還是會(huì)返回一個(gè)新的數(shù)據(jù)戳,這也是StampedLock不可重入的原因。


      ? tampedLockReentrantReadWriteLock 一樣,StampedLock 同樣適合讀多寫(xiě)少的業(yè)務(wù)場(chǎng)景,可以作為 ReentrantReadWriteLock的替代品,性能更好。

      StampedLock 適合什么場(chǎng)景?

      java實(shí)現(xiàn)多線(xiàn)程的幾種方式

      1繼承Thread類(lèi):

      ? 1.創(chuàng)建多個(gè)線(xiàn)程,調(diào)用start方法,啟動(dòng)線(xiàn)程的時(shí)候,并不是調(diào)用線(xiàn)程類(lèi)的run方法,而是調(diào)用了線(xiàn)程類(lèi)的start方法。那么我們能不能調(diào)用run方法呢?答案是肯定的,因?yàn)閞un方法是一個(gè)public聲明的方法,因此我們是可以調(diào)用的,但是如果我們調(diào)用了run方法,那么這個(gè)方法將會(huì)作為一個(gè)普通的方法被調(diào)用,并不會(huì)開(kāi)啟線(xiàn)程。這里實(shí)際上是采用了設(shè)計(jì)模式中的模板方法模式,Thread類(lèi)作為模板,而run方法是在變化的,因此放到子類(lèi)來(lái)實(shí)現(xiàn)。(能調(diào)用,但是就不算開(kāi)啟線(xiàn)程了)
      ? 2。指定線(xiàn)程名稱(chēng),不指定的話(huà),系統(tǒng)會(huì)默認(rèn)指定線(xiàn)程名,命名規(guī)則是Thread-N的形式。但是為了排查問(wèn)題方便,建議在創(chuàng)建線(xiàn)程的時(shí)候指定一個(gè)合理的線(xiàn)程名字。下面的代碼是不使用線(xiàn)程名的樣子。

      2實(shí)現(xiàn)runnable接口:

      ? 1.將低程序的耦合度

      ? 2.Runnabl接口中只定義一個(gè)方法run方法。

      ? 3.利用線(xiàn)程任務(wù)和線(xiàn)程的控制分離,實(shí)現(xiàn)了線(xiàn)程的解耦。我們要實(shí)現(xiàn)一個(gè)線(xiàn)程,可以借助Thread類(lèi),Thread類(lèi)要執(zhí)行的任務(wù)就可以由實(shí)現(xiàn)了Runnable接口的類(lèi)來(lái)處理

      ? 4.1)創(chuàng)建線(xiàn)程任務(wù)

      ? 2)創(chuàng)建可運(yùn)行類(lèi):

      	線(xiàn)程任務(wù)和線(xiàn)程的控制分離,那么一個(gè)線(xiàn)程任務(wù)可以提交給多個(gè)線(xiàn)程來(lái)執(zhí)行。這是很有用的,比如車(chē)站的售票窗口,每個(gè)窗口可以看做是一個(gè)線(xiàn)程,他們每個(gè)窗口做的事情都是一樣的,也就是售票。這樣我們程序在模擬現(xiàn)實(shí)的時(shí)候就可以定義一個(gè)售票任務(wù),讓多個(gè)窗口同時(shí)執(zhí)行這一個(gè)任務(wù)。那么如果要改動(dòng)任務(wù)執(zhí)行計(jì)劃,只要修改線(xiàn)程任務(wù)類(lèi),所有的線(xiàn)程就都會(huì)按照修改后的來(lái)執(zhí)行。相比較繼承Thread類(lèi)的方式來(lái)創(chuàng)建線(xiàn)程的方式,實(shí)現(xiàn)Runnable接口是更為常用的。
      

      ? 3)lamba方式創(chuàng)建線(xiàn)程任務(wù):簡(jiǎn)化內(nèi)部類(lèi)的編寫(xiě)。

      3使用內(nèi)部類(lèi)的方式

      ? 線(xiàn)程只想執(zhí)行一次的時(shí)候,就可以使用內(nèi)部類(lèi),可以少定義一個(gè)類(lèi)。就分為兩種情況:

      ? 1)繼承Thread類(lèi)

      ? 2)實(shí)現(xiàn)runnable接口。

      ? 當(dāng)兩者同時(shí)內(nèi)部實(shí)現(xiàn)時(shí),忽略runnable的方式

      代碼如下:

       // 基于子類(lèi)的方式
              new Thread() {
                  @Override
                  public void run() {
                      while (true) {
                          printThreadInfo();
                      }
                  }
              }.start();
      
          // 基于接口的實(shí)現(xiàn)
          new Thread(new Runnable() {
              @Override
              public void run() {
                  while (true) {
                      printThreadInfo();
                  }
              }
          }).start();
      }
      

      ? lambda方式改造:

      // 使用lambda的形式
      new Thread(() -> {
          while (true) {
              printThreadInfo();
          }
      }).start();
      
      // 對(duì)比不使用lambda的形式
      new Thread(new Runnable() {
          @Override
          public void run() {
              while (true) {
                  printThreadInfo();
              }
          }
      }).start();
      

      4定時(shí)器

      ? 定時(shí)器可以說(shuō)是一種基于線(xiàn)程的一個(gè)工具類(lèi),可以定時(shí)的來(lái)執(zhí)行某個(gè)任務(wù)。在應(yīng)用中經(jīng)常需要定期執(zhí)行一些操作,比如要在凌晨的時(shí)候匯總一些數(shù)據(jù),比如要每隔10分鐘抓取一次某個(gè)網(wǎng)站上的數(shù)據(jù)等等,總之計(jì)時(shí)器無(wú)處不在。

      ? 1.指定時(shí)間點(diǎn)執(zhí)行

      import java.text.SimpleDateFormat;
      import java.util.Timer;
      import java.util.TimerTask;
      public class CreateThreadDemo9_Timer {
      
          private static final SimpleDateFormat format =
                  new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
      
          public static void main(String[] args) throws Exception {
              ```
              // 創(chuàng)建定時(shí)器
              Timer timer = new Timer();
      
              // 提交計(jì)劃任務(wù)
              timer.schedule(new TimerTask() {
                  @Override
                  public void run() {
                      System.out.println("定時(shí)任務(wù)執(zhí)行了...");
                  }
              }, format.parse("2017-10-11 22:00:00"));
              ```
          }
      }
      

      ? 2.間隔時(shí)間重復(fù)執(zhí)行

      		// 提交計(jì)劃任務(wù)
              timer.schedule(new TimerTask() {
                  @Override
                  public void run() {
                      System.out.println("定時(shí)任務(wù)執(zhí)行了...");
                  }
              },
         		new Date(), 1000);
      

      5帶返回值的線(xiàn)程實(shí)現(xiàn)方式(Callable接口)

      •  imort java.util.concurrent.Callable;
         import java.util.concurrent.FutureTask;
         
         /**
         
          * 帶返回值的方式
            */
            public class CreateThreadDemo11_Callable {
         
            public static void main(String[] args) throws Exception {
         
                // 創(chuàng)建線(xiàn)程任務(wù)
                Callable<Integer> call = () -> {
                    System.out.println("線(xiàn)程任務(wù)開(kāi)始執(zhí)行了....");
                    Thread.sleep(2000);
                    return 1;
                };
                
                // 將任務(wù)封裝為FutureTask
                FutureTask<Integer> task = new FutureTask<>(call);
                
                // 開(kāi)啟線(xiàn)程,執(zhí)行線(xiàn)程任務(wù)
                new Thread(task).start();
                
                // ====================
                // 這里是在線(xiàn)程啟動(dòng)之后,線(xiàn)程結(jié)果返回之前
                System.out.println("這里可以為所欲為....");
                // ====================
                
                // 為所欲為完畢之后,拿到線(xiàn)程的執(zhí)行結(jié)果
                Integer result = task.get();
                System.out.println("主線(xiàn)程中拿到異步任務(wù)執(zhí)行的結(jié)果為:" + result);
         
            }
            }
        

      6基于線(xiàn)程池的方式實(shí)現(xiàn)

      	我們知道,線(xiàn)程和數(shù)據(jù)庫(kù)連接這些資源都是非常寶貴的資源。那么每次需要的時(shí)候創(chuàng)建,不需要的時(shí)候銷(xiāo)毀,是非常浪費(fèi)資源的。那么我們就可以使用緩存的策略,也就是使用線(xiàn)程池。當(dāng)然了,線(xiàn)程池也不需要我們來(lái)實(shí)現(xiàn),jdk的官方也給我們提供了API。
      
      ?~~~java
      import java.util.concurrent.ExecutorService;
      import java.util.concurrent.Executors;
      public class CreateThreadDemo12_ThreadPool {
      public static void main(String[] args) throws Exception {
      ```
      // 創(chuàng)建固定大小的線(xiàn)程池
      ExecutorService threadPool = Executors.newFixedThreadPool(10);
      
      while (true) {
          // 提交多個(gè)線(xiàn)程任務(wù),并執(zhí)行
          threadPool.execute(new Runnable() {
              @Override
              public void run() {
                  printThreadInfo();
              }
          });
      }
      ```
      }
      
      /**
       * 輸出當(dāng)前線(xiàn)程的信息
         */
         private static void printThreadInfo() {
         System.out.println("當(dāng)前運(yùn)行的線(xiàn)程名為: " + Thread.currentThread().getName());
         try {
             Thread.sleep(1000);
         } catch (Exception e) {
             throw new RuntimeException(e);
         }
      }
      }
      ?~~~
      

      ?

      ThreadLocal

      ?

      ? ThreadLocal類(lèi)主要解決的就是讓每個(gè)線(xiàn)程綁定自己的值。 訪問(wèn)一個(gè)threadLocal變量,則每一個(gè)線(xiàn)程都會(huì)有這個(gè)變量的本地副本。

      ? ThreadLocal類(lèi)主要解決的就是讓每個(gè)線(xiàn)程綁定自己的值,可以將ThreadLocal類(lèi)形象的比喻成存放數(shù)據(jù)的盒子,盒子中可以存儲(chǔ)每個(gè)線(xiàn)程的私有數(shù)據(jù)。

      TheadLocal原理:

      從上面Thread類(lèi) 源代碼可以看出Thread 類(lèi)中有一個(gè) threadLocals 和 一個(gè) inheritableThreadLocals 變量,它們都是 ThreadLocalMap 類(lèi)型的變量,我們可以把 ThreadLocalMap 理解為ThreadLocal 類(lèi)實(shí)現(xiàn)的定制化的 HashMap。默認(rèn)情況下這兩個(gè)變量都是 null,只有當(dāng)前線(xiàn)程調(diào)用 ThreadLocal 類(lèi)的 setget方法時(shí)才創(chuàng)建它們,實(shí)際上調(diào)用這兩個(gè)方法的時(shí)候,我們調(diào)用的是ThreadLocalMap類(lèi)對(duì)應(yīng)的 get()set()方法。

      過(guò)上面這些內(nèi)容,我們足以通過(guò)猜測(cè)得出結(jié)論:最終的變量是放在了當(dāng)前線(xiàn)程的 ThreadLocalMap 中,并不是存在 ThreadLocal 上,ThreadLocal 可以理解為只是ThreadLocalMap的封裝,傳遞了變量值。 ThrealLocal 類(lèi)中可以通過(guò)Thread.currentThread()獲取到當(dāng)前線(xiàn)程對(duì)象后,直接通過(guò)getMap(Thread t)可以訪問(wèn)到該線(xiàn)程的ThreadLocalMap對(duì)象。

      **每個(gè)Thread中都具備一個(gè)ThreadLocalMap,而ThreadLocalMap可以存儲(chǔ)以ThreadLocal為 key ,Object 對(duì)象為 value 的鍵值對(duì)。

      image-20230911091251266

      ThreadLocal內(nèi)存泄漏問(wèn)題:

      image-20230911091303773


      線(xiàn)程池

      什么線(xiàn)程池

      為什么使用線(xiàn)程池

      ? 池化技術(shù)的思想主要是為了減少每次獲取資源的消耗,提高對(duì)資源的利用率。

      ? 線(xiàn)程池提供了一種限制和管理資源(包括執(zhí)行一個(gè)任務(wù))的方式。 每個(gè)線(xiàn)程池還維護(hù)一些基本統(tǒng)計(jì)信息,例如已完成任務(wù)的數(shù)量。

      image-20230909100145045

      創(chuàng)建線(xiàn)程池的方式

      1通過(guò)ThreadPoolExecutor構(gòu)造函數(shù)來(lái)創(chuàng)建(推薦)。

      2通過(guò) Executor 框架的工具類(lèi) Executors 來(lái)創(chuàng)建。

      ? image-20230909101358784

      不推薦內(nèi)置線(xiàn)程池方法來(lái)創(chuàng)建線(xiàn)程池。

      image-20230909101708017

      線(xiàn)程池常見(jiàn)參數(shù)

      /**
       * 用給定的初始參數(shù)創(chuàng)建一個(gè)新的ThreadPoolExecutor。
       */
      public ThreadPoolExecutor(int corePoolSize,//線(xiàn)程池的核心線(xiàn)程數(shù)量
                                int maximumPoolSize,//線(xiàn)程池的最大線(xiàn)程數(shù)
                                long keepAliveTime,//當(dāng)線(xiàn)程數(shù)大于核心線(xiàn)程數(shù)時(shí),多余的空閑線(xiàn)程存活的最長(zhǎng)時(shí)間
                                TimeUnit unit,//時(shí)間單位
                                BlockingQueue<Runnable> workQueue,//任務(wù)隊(duì)列,用來(lái)儲(chǔ)存等待執(zhí)行任務(wù)的隊(duì)列
                                ThreadFactory threadFactory,//線(xiàn)程工廠,用來(lái)創(chuàng)建線(xiàn)程,一般默認(rèn)即可
                                RejectedExecutionHandler handler//拒絕策略,當(dāng)提交的任務(wù)過(guò)多而不能及時(shí)處理時(shí),我們可以定制策略來(lái)處理任務(wù)
                                 ) {
          if (corePoolSize < 0 ||
              maximumPoolSize <= 0 ||
              maximumPoolSize < corePoolSize ||
              keepAliveTime < 0)
              throw new IllegalArgumentException();
          if (workQueue == null || threadFactory == null || handler == null)
              throw new NullPointerException();
          this.corePoolSize = corePoolSize;
          this.maximumPoolSize = maximumPoolSize;
          this.workQueue = workQueue;
          this.keepAliveTime = unit.toNanos(keepAliveTime);
          this.threadFactory = threadFactory;
          this.handler = handler;
      }
      

      image-20230909102423778

      線(xiàn)程池的飽和策略

      ? 如果當(dāng)前同時(shí)運(yùn)行的線(xiàn)程數(shù)量達(dá)到最大線(xiàn)程數(shù)量并且隊(duì)列也已經(jīng)被放滿(mǎn)了任務(wù)時(shí),ThreadPoolTaskExecutor 定義一些策略:

      image-20230909152509729

      線(xiàn)程池常用的阻塞隊(duì)列

      ? image-20230911094120836

      應(yīng)為當(dāng)隊(duì)列無(wú)界是,既無(wú)法達(dá)到隊(duì)列的最大值,所以不需要擴(kuò)容核心線(xiàn)程數(shù),所以最大創(chuàng)建的線(xiàn)程為核心線(xiàn)程數(shù)。

      線(xiàn)程池處理任務(wù)流程

      image-20230911095311909

      如何設(shè)定線(xiàn)程池大小

      ? 多線(xiàn)程這個(gè)場(chǎng)景來(lái)說(shuō)主要是增加了上下文切換成本

      image-20230912214251667

      image-20230912214615293

      image-20230912214728382

      如何動(dòng)態(tài)創(chuàng)建線(xiàn)程池參數(shù)(美團(tuán)的解決方案)

      ? 線(xiàn)程池參數(shù)動(dòng)態(tài)化。

      image-20230912220304390

      image-20230912220916392

      動(dòng)態(tài)化的原理

      image-20230912221120577

      經(jīng)過(guò)前面兩個(gè)方法的分析,我們知道了最大線(xiàn)程數(shù)核心線(xiàn)程數(shù)可以動(dòng)態(tài)調(diào)整。

      如何動(dòng)態(tài)指定等待隊(duì)列的長(zhǎng)度

      ? image-20230912221522520

      ResizableCapacityLinkedBlockIngQueue 的隊(duì)列:

      定義一個(gè)隊(duì)列,讓其可以對(duì) Capacity 參數(shù)進(jìn)行修改即可。操作起來(lái)也非常方便,把 LinkedBlockingQueue 粘貼一份出來(lái),修改個(gè)名字,然后把 Capacity 參數(shù)的 final 修飾符去掉,并提供其對(duì)應(yīng)的 get/set 方法。

      image-20230912221651770

      Future類(lèi)

      作用:

      ? 具體來(lái)說(shuō)是這樣的:當(dāng)我們執(zhí)行某一耗時(shí)的任務(wù)時(shí),可以將這個(gè)耗時(shí)任務(wù)交給一個(gè)子線(xiàn)程去異步執(zhí)行,同時(shí)我們可以干點(diǎn)其他事情,不用傻傻等待耗時(shí)任務(wù)執(zhí)行完成。等我們的事情干完后,我們?cè)偻ㄟ^(guò) Future 類(lèi)獲取到耗時(shí)任務(wù)的執(zhí)行結(jié)果。這樣一來(lái),程序的執(zhí)行效率就明顯提高了。

      ? 其實(shí)就是多線(xiàn)程中經(jīng)典的 Future 模式,你可以將其看作是一種設(shè)計(jì)模式,核心思想是異步調(diào)用,主要用在多線(xiàn)程領(lǐng)域,并非 Java 語(yǔ)言獨(dú)有。

      image-20230912223357498

      image-20230912223411012

      Callable與Futrue的關(guān)系:

      FutureTask 提供了 Future 接口的基本實(shí)現(xiàn),常用來(lái)封裝 CallableRunnable,具有取消任務(wù)、查看任務(wù)是否執(zhí)行完成以及獲取任務(wù)執(zhí)行結(jié)果的方法。ExecutorService.submit() 方法返回的其實(shí)就是 Future 的實(shí)現(xiàn)類(lèi) FutureTask

      <T> Future<T> submit(Callable<T> task);
      Future<?> submit(Runnable task); 
      

      FutureTask 有兩個(gè)構(gòu)造函數(shù),可傳入 Callable 或者 Runnable 對(duì)象。實(shí)際上,傳入 Runnable 對(duì)象也會(huì)在方法內(nèi)部轉(zhuǎn)換為Callable 對(duì)象。

      public FutureTask(Callable<V> callable) {
          if (callable == null)
              throw new NullPointerException();
          this.callable = callable;
          this.state = NEW;
      }
      public FutureTask(Runnable runnable, V result) {
          // 通過(guò)適配器RunnableAdapter來(lái)將Runnable對(duì)象runnable轉(zhuǎn)換成Callable對(duì)象
          this.callable = Executors.callable(runnable, result);
          this.state = NEW;
      }
      

      FutureTask相當(dāng)于對(duì)Callable 進(jìn)行了封裝,管理著任務(wù)執(zhí)行的情況,存儲(chǔ)了 Callablecall 方法的任務(wù)執(zhí)行結(jié)果

      CompletableFuture 類(lèi)的作用

      image-20230912224201734

      AQS(AbstractQueuedSynchronizer)

      ? 抽象隊(duì)列同步器java.util.concurrent.locks 包下面。

      ? AQS 就是一個(gè)抽象類(lèi),主要用來(lái)構(gòu)建同步器

      ? AQS 為構(gòu)建鎖和同步器提供了一些通用功能的實(shí)現(xiàn),因此,使用 AQS 能簡(jiǎn)單且高效地構(gòu)造出應(yīng)用廣泛的大量的同步器,比如我們提到的 ReentrantLockSemaphore,其他的諸如 ReentrantReadWriteLockSynchronousQueue等等皆是基于 AQS 的。

      AQS的原理

      ? 1.如果被請(qǐng)求的資源空閑,則當(dāng)前請(qǐng)求資源的線(xiàn)程設(shè)置為有效的工作線(xiàn)程,并且將共享資源設(shè)置為共享狀態(tài)。

      ? 2.如果請(qǐng)求得資源被占用時(shí),那么就需要一套線(xiàn)程阻塞等待以及被喚醒時(shí)鎖分配的機(jī)制。這個(gè)機(jī)制AQS就是用CLH隊(duì)列實(shí)現(xiàn)的,即將暫時(shí)獲取不到鎖的線(xiàn)程加入到隊(duì)列中。

      ? CLH隊(duì)列是一個(gè)虛擬的雙向隊(duì)列。一個(gè)線(xiàn)程相當(dāng)于一個(gè)節(jié)點(diǎn),一個(gè)節(jié)點(diǎn)保存著1)線(xiàn)程的引用 ;2)當(dāng)前節(jié)點(diǎn)在隊(duì)列中的狀態(tài),3)前驅(qū)節(jié)點(diǎn),4)后驅(qū)節(jié)點(diǎn)。

      ? image-20230913084538695

      img

      AQS使用int成員變量state表示同步狀態(tài),通過(guò)內(nèi)置的線(xiàn)程等待隊(duì)列來(lái)完成獲取資源線(xiàn)程的排隊(duì)工作。

      state由volatile關(guān)鍵字修飾,用于展示當(dāng)前臨界資源的獲鎖情況。

      // 共享變量,使用volatile修飾保證線(xiàn)程可見(jiàn)性
      private volatile int state;
      

      image-20230913085728033

      以CountDownLatch為例:

      image-20230913085742750

      Semaphore的用處

      ? synchronized和ReentrantLock都是一次只允許一個(gè)線(xiàn)程訪問(wèn)某個(gè)資源。

      ? semaphore可以用來(lái)控制同時(shí)訪問(wèn)特定資源的線(xiàn)程數(shù)量。

      image-20230913091337554

      當(dāng)初始資源個(gè)數(shù)為1時(shí),Semaphore退化為排他鎖。

      兩種模式

      ? 1.公平模式:調(diào)用acquire方法的順序就是獲取許可證的順序,遵循FIFO。

      ? 2.非公平模式:搶占式的。

      image-20230913091940545

      Semaphore的原理:

      ? 共享鎖的一種實(shí)現(xiàn),默認(rèn)構(gòu)造AQS的state的值為permits,可以將permits的值理解為許可證的數(shù)量,只有拿到許可證的線(xiàn)程才能執(zhí)行。

      調(diào)用semaphore。acquire(),嘗試獲取許可證,

      ? 如果state>=0,表示可以獲取成功。

      ? 獲取成功的話(huà),使用CAS操作去修改state的值使得state=state-1。、

      ? 如果state<0,則表示許可證數(shù)量不足。此時(shí)加入阻塞隊(duì)列,掛起當(dāng)前線(xiàn)程。

      image-20230913092739056

      CountDownLatch的用處

      ? CountDownLatch 允許 count 個(gè)線(xiàn)程阻塞在一個(gè)地方,直至所有線(xiàn)程的任務(wù)都執(zhí)行完畢。

      CountDownLatch 是一次性的,計(jì)數(shù)器的值只能在構(gòu)造方法中初始化一次,之后沒(méi)有任何機(jī)制再次對(duì)其設(shè)置值,當(dāng) CountDownLatch 使用完畢后,它不能再次被使用。

      CountDownLatch的原理

      ? 共享鎖的一種實(shí)現(xiàn)。默認(rèn)構(gòu)造AQS的state值為count。image-20230913094116372

      CountDownLatch的場(chǎng)景:

      image-20230913094741572

      偽代碼如下:

      public class CountDownLatchExample1 {
          // 處理文件的數(shù)量
          private static final int threadCount = 6;
          public static void main(String[] args) throws InterruptedException {
              // 創(chuàng)建一個(gè)具有固定線(xiàn)程數(shù)量的線(xiàn)程池對(duì)象(推薦使用構(gòu)造方法創(chuàng)建)
              ExecutorService threadPool = Executors.newFixedThreadPool(10);
              final CountDownLatch countDownLatch = new CountDownLatch(threadCount);
              for (int i = 0; i < threadCount; i++) {
                  final int threadnum = i;
                  threadPool.execute(() -> {
                      try {
                          //處理文件的業(yè)務(wù)操作
                          //......
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      } finally {
                          //表示一個(gè)文件已經(jīng)被完成
                          countDownLatch.countDown();
                      }
      
                  });
              }
              countDownLatch.await();
              threadPool.shutdown();
              System.out.println("finish");
          }
      }
      

      CyclicBarrier的作用

      ? 可循環(huán)的屏障image-20230913095923137

      CyclicBarrier的原理

      ? CyclicBarrier內(nèi)部通過(guò)一個(gè)count變量作為計(jì)數(shù)器,count的初始值為parties屬性為初始值,每當(dāng)一個(gè)線(xiàn)程到了柵欄這里了,那么就將計(jì)數(shù)器減 1。如果 count 值為 0 了,表示這是這一代最后一個(gè)線(xiàn)程到達(dá)柵欄,就嘗試執(zhí)行我們構(gòu)造方法中輸入的任務(wù)。

      image-20230913102044703

      image-20230913102148537

      await的使用

      在Java中,"await"方法通常與多線(xiàn)程編程和并發(fā)控制相關(guān)。這個(gè)方法通常用于等待某個(gè)條件或事件的發(fā)生,然后暫停當(dāng)前線(xiàn)程的執(zhí)行,直到條件滿(mǎn)足或事件發(fā)生后再繼續(xù)執(zhí)行。"await"方法通常與信號(hào)量、條件變量、鎖或線(xiàn)程池等并發(fā)控制機(jī)制一起使用,以實(shí)現(xiàn)線(xiàn)程的同步和協(xié)作。 在Java中,常見(jiàn)的使用"await"方法的類(lèi)和接口包括:

      1. CountDownLatch(倒計(jì)數(shù)門(mén)閂):使用await()方法等待計(jì)數(shù)器歸零。

      2. CyclicBarrier(循環(huán)屏障):使用await()方法等待到達(dá)指定的屏障位置。

      3. Phaser(階段器):使用awaitAdvance()方法等待其他參與者到達(dá)相同的階段。

      4. Condition(條件):在使用ReentrantLock或ReentrantReadWriteLock時(shí),可以使用await()方法等待條件滿(mǎn)足。

        需要注意的是,"await"方法必須在某種線(xiàn)程同步機(jī)制的作用域內(nèi)使用,并且通常需要正確設(shè)置條件或事件的觸發(fā)條件,以避免線(xiàn)程永遠(yuǎn)等待或出現(xiàn)死鎖等并發(fā)問(wèn)題。

      JMM(Java內(nèi)存模型)

      CPU緩存模型

      ? 解決CPU處理速度和內(nèi)存不匹配的問(wèn)題。

      ? CPUCache工作方式可能會(huì)導(dǎo)致內(nèi)存緩存不一致性的問(wèn)題。image-20230913105637563

      ? 為了解決這個(gè)問(wèn)題:通過(guò)制定緩存一致協(xié)議(MESI協(xié)議),或其他手段。image-20230913105926856

      ?

      Java線(xiàn)程池詳解

      監(jiān)控線(xiàn)程池

      ? SpringBoot 中的 Actuator 組件。自己寫(xiě)一個(gè)監(jiān)控線(xiàn)程池的HealthContributor,(https://www.codenong.com/cs110918477/)

      image-20230914093705754

      建議不同類(lèi)別的業(yè)務(wù)用不同的線(xiàn)程池

      一個(gè)線(xiàn)程池執(zhí)行父子任務(wù)(父等子的回應(yīng),子等父的釋放資源)容易發(fā)生死鎖。

      image-20230914094335603

      線(xiàn)程池和ThreadLocal共用的坑

      image-20230914094901185

      Java常見(jiàn)并發(fā)容器總結(jié)

      基本都在java.util.concurren包里。

      image-20230914095305775

      ConcurrentHashMap

      ? 1.7版本Segment數(shù)組+HashEntry數(shù)組+鏈表

      image-20230914100412071

      1.8版本Node數(shù)組+鏈表+紅黑樹(shù)

      image-20230914100449918

      CopyOnWriteArrayList

      Java1.5版本使用的是vetor,但是該容器增刪改查基本都加了synchornized.相當(dāng)于給vector加了一把大鎖,性能非常低下。

      JUC中唯一的線(xiàn)程安全Lisy就是這個(gè)CopyOnWriteArrayList.

      寫(xiě)時(shí)復(fù)制(Copy-On-Write)的策略(只有寫(xiě)寫(xiě)互斥);

      image-20230914101216031

      ConcurrentLinkedQueue(非阻塞隊(duì)列)(無(wú)鎖)

      ? 阻塞隊(duì)列可以通過(guò)加鎖來(lái)實(shí)現(xiàn),非阻塞隊(duì)列可以通過(guò) CAS 操作實(shí)現(xiàn)。

      主要使用CAS非阻塞算法來(lái)實(shí)現(xiàn)線(xiàn)程安全。其使用鏈表作為數(shù)據(jù)結(jié)構(gòu)。

      BlockingQueue(阻塞隊(duì)列)(是一個(gè)接口)(以后好好看看

      ArrayBlockingQueue(實(shí)現(xiàn)類(lèi))(有界)

      LinkedBlockingQueue(實(shí)現(xiàn)類(lèi)無(wú)界)(單向鏈表)

      PriorityBlockingQueue(實(shí)現(xiàn)類(lèi)無(wú)界,支持優(yōu)先級(jí))image-20230914102624707

      ConcurrentSkipListMap

      跳表(時(shí)間復(fù)雜度O(Logn))

      ? 所以在并發(fā)數(shù)據(jù)結(jié)構(gòu)中,JDK 使用跳表來(lái)實(shí)現(xiàn)一個(gè) Map。 2級(jí)索引跳表

      上圖是一個(gè)2級(jí)索引跳表

      image-20230914103230214

      跳表是一種利用空間換時(shí)間的算法。

      image-20230914103314105

      Atomic原子類(lèi)總結(jié)

      ? 在java.util.concurrent.atmoic包下面

      image-20230914104243897

      原子類(lèi)可分為4類(lèi)。

      image-20230914105633623

      image-20230914105640828

      一般都是通過(guò)CAS操作,比synchornized的操作開(kāi)銷(xiāo)小多了。

      ThreadLocal詳解

      img

      具體使用

      public class ThreadLocalTest {
          private List<String> messages = Lists.newArrayList();
          public static final ThreadLocal<ThreadLocalTest> holder = 			         ThreadLocal.withInitial(ThreadLocalTest::new);
          public static void add(String message) {
              holder.get().messages.add(message);
          }
      
          public static List<String> clear() {
              List<String> messages = holder.get().messages;
              holder.remove();
      
              System.out.println("size: " + holder.get().messages.size());
              return messages;
          }
      
          public static void main(String[] args) {
              ThreadLocalTest.add("一枝花算不算浪漫");
              System.out.println(holder.get().messages);
              ThreadLocalTest.clear();
          }
      }
      

      需要理解的是:

      public static final ThreadLocal<ThreadLocalTest> holder = 			         ThreadLocal.withInitial(ThreadLocalTest::new);
      

      ? 當(dāng)我們創(chuàng)建一個(gè)ThreadLocal對(duì)象時(shí),我們可以使用withInitial方法為其指定一個(gè)供應(yīng)商函數(shù)(Supplier Function)。供應(yīng)商函數(shù)在需要的時(shí)候創(chuàng)建初始值,返回一個(gè)新的對(duì)象作為線(xiàn)程的局部變量。 在這個(gè)例子中,ThreadLocalTest.holder是一個(gè)ThreadLocal<ThreadLocalTest>對(duì)象,它的泛型參數(shù)是ThreadLocalTest,表示每個(gè)線(xiàn)程都將擁有一個(gè)ThreadLocalTest對(duì)象作為其局部變量ThreadLocalTest.holder使用了withInitial方法,并傳入了一個(gè)方法引用ThreadLocalTest::new作為供應(yīng)商函數(shù)。這意味著當(dāng)一個(gè)線(xiàn)程首次訪問(wèn)ThreadLocalTest.holderget()方法時(shí),會(huì)調(diào)用ThreadLocalTest::new方法創(chuàng)建一個(gè)新的ThreadLocalTest對(duì)象作為該線(xiàn)程的局部變量。 換句話(huà)說(shuō),每個(gè)線(xiàn)程都有自己的ThreadLocalTest對(duì)象,通過(guò)ThreadLocalTest.holder.get()獲取。如果線(xiàn)程首次訪問(wèn)holder時(shí)還沒(méi)有創(chuàng)建過(guò)ThreadLocalTest對(duì)象,withInitial指定的供應(yīng)商函數(shù)會(huì)被調(diào)用來(lái)創(chuàng)建一個(gè)新的對(duì)象。而后續(xù)的訪問(wèn)會(huì)返回該線(xiàn)程已經(jīng)創(chuàng)建的那個(gè)對(duì)象。 這種方式保證了每個(gè)線(xiàn)程都擁有獨(dú)立的對(duì)象實(shí)例,而不會(huì)相互影響。每個(gè)線(xiàn)程都可以向自己的ThreadLocalTest對(duì)象的messages列表中添加消息,而不會(huì)影響其他線(xiàn)程的列表。 希望這樣解釋更詳細(xì)一些,如果還有疑問(wèn),請(qǐng)隨時(shí)問(wèn)我!??

      ThreadLocal的數(shù)據(jù)結(jié)構(gòu)

      image-20230919161828361

      GC 之后 key 是否為 null?

      https://blog.csdn.net/thewindkee/article/details/103726942

      ThreadLocal的內(nèi)存泄漏:image-20230920085323031

      ThreadLocal的Hash算法

      ?

      int i = key.threadLocalHashCode & (len-1);
      

      image-20230920090359185

      ThreadLocalHash沖突

      ? img

      ThreadLocalMap過(guò)期Key的探測(cè)式清理流程:

      ? 共有兩種過(guò)期Key的數(shù)據(jù)清理方式:探測(cè)式清理啟發(fā)式清理

      探測(cè)式清理:

      ? 離得更近,變位置。

      image-20230920093603460

      啟發(fā)式清理:

      ? image-20230921083356837

      image-20230921083617885

      ThreadLocal擴(kuò)容機(jī)制

      在ThreadLocal.set()的最后,如果執(zhí)行完清理式工作后,未清理到任何數(shù)據(jù),且當(dāng)前散列數(shù)據(jù)中Entry的數(shù)量達(dá)到了列表的擴(kuò)容閾值(len*2/3),就開(kāi)始執(zhí)行rehash()邏輯。

      image-20230921084412889

      rehash()的閾值為threshold*2/3

      擴(kuò)容的閾值:只是通過(guò)image-20230921084645433

      擴(kuò)容后的大小為oldLen*2.

      image-20230921085523348

      Get方法

      第一種情況:通過(guò)key值查找出散列表中slot的位置,然后通過(guò)判斷slot位置的key是否與查找的key值相同。相同則返回

      第二種情況:slot位置的Entry.key和查找的key不一致:

      ? 不一致時(shí),往后迭代查找。當(dāng)Entry.key=null,觸發(fā)一次探測(cè)式數(shù)回收操作。

      InheritableThreadLocal

      posted on 2023-09-21 09:40  一個(gè)癡迷于技術(shù)的碼農(nóng)  閱讀(41)  評(píng)論(0)    收藏  舉報(bào)
      主站蜘蛛池模板: 中文 在线 日韩 亚洲 欧美| www内射国产在线观看| 新干县| 亚洲狼人久久伊人久久伊| 国产综合精品一区二区在线| 精品国产乱子伦一区二区三区| 国产影片AV级毛片特别刺激 | 视频二区中文字幕在线| 日韩一区二区三区水蜜桃| 国产高清在线不卡一区| 欧美丰满熟妇xxxx性| 嫩草欧美曰韩国产大片| 福利一区二区1000| 中文字幕乱码中文乱码毛片| 国产视频最新| 岛国一区二区三区高清视频| 亚洲春色在线视频| 狠狠色噜噜狠狠狠狠蜜桃| 精品无码久久久久久尤物| 日韩精品中文字幕无码一区| 久久亚洲美女精品国产精品| 久热久热免费在线观视频| 少妇真人直播免费视频| 成av免费大片黄在线观看| 亚洲第三十四九中文字幕| 欧美精品一产区二产区| 国产玖玖视频| 亚洲精品一区二区三天美| 农民人伦一区二区三区| 九九热精品在线观看| 久久热在线视频精品视频| 成人无码精品1区2区3区免费看| 亚洲精品综合网在线8050影院| 素人视频亚洲十一十二区| 国产v亚洲v天堂无码久久久| 丰满少妇熟乱xxxxx视频| 国产一区二区三区在线观看免费| 亚洲日韩精品一区二区三区| 亚洲人精品午夜射精日韩| 亚洲一区中文字幕人妻| 稻城县|