java并發(fā)編程藝術(shù)讀書(shū)筆記

1.減少上下文切換的方法有無(wú)鎖并發(fā)編程宴合、CAS算法拴泌、使用最少線(xiàn)程和使用協(xié)程慎皱。

無(wú)所并發(fā)編程:多線(xiàn)程競(jìng)爭(zhēng)鎖時(shí),會(huì)引起上下文切換,所以多線(xiàn)程處理數(shù)據(jù)時(shí),可以用一些辦法來(lái)避免使用鎖,如將數(shù)據(jù)的ID按照Hash算法取模分段献联,不同的線(xiàn)程處理不同段的數(shù)據(jù);

CAS算法:Java的Atomic包使用CAS算法來(lái)更新數(shù)據(jù)何址,而不需要加鎖里逆;

使用最少線(xiàn)程:避免創(chuàng)建不需要的線(xiàn)程,比如任務(wù)很少用爪,但是創(chuàng)建了很多線(xiàn)程來(lái)處理原押,這樣會(huì)造成大量線(xiàn)程處于等待狀態(tài);

協(xié)程:在單線(xiàn)程里實(shí)現(xiàn)多任務(wù)的調(diào)度偎血,并在單線(xiàn)程里維持多個(gè)任務(wù)間的切換诸衔。

2.避免死鎖的幾個(gè)常見(jiàn)方法:

  • 避免一個(gè)線(xiàn)程同時(shí)獲取多個(gè)鎖;
  • 避免一個(gè)線(xiàn)程在鎖內(nèi)同時(shí)占用多個(gè)資源颇玷,盡量保證每個(gè)鎖只占用一個(gè)資源笨农;
  • 嘗試使用定時(shí)鎖,使用lock.tryLock(timeout)來(lái)替代使用內(nèi)部鎖機(jī)制帖渠;
  • 對(duì)于數(shù)據(jù)庫(kù)鎖谒亦,加鎖和解鎖必須在一個(gè)數(shù)據(jù)庫(kù)鏈接里,否則會(huì)出現(xiàn)解鎖失敗的情況空郊。

3.在Java中份招,鎖一共有四種,級(jí)別從低到高一次為:無(wú)所狀態(tài)狞甚,偏向鎖狀態(tài)锁摔,輕量級(jí)鎖狀態(tài)和重量級(jí)鎖狀態(tài)。這幾個(gè)狀態(tài)會(huì)隨著競(jìng)爭(zhēng)情況逐漸升級(jí)哼审,鎖可以升級(jí)但不能降級(jí)谐腰,意味著偏向鎖升級(jí)為輕量級(jí)鎖后不能降級(jí)為偏向鎖孕豹。

4.在大多數(shù)情況下,鎖不僅不存在多線(xiàn)程競(jìng)爭(zhēng)怔蚌,而且總是由同一線(xiàn)程多次獲得,為了讓線(xiàn)程獲得鎖的代價(jià)更低而引入了偏向鎖旁赊。當(dāng)一個(gè)線(xiàn)程訪問(wèn)同步代碼塊獲取鎖時(shí)桦踊,會(huì)在對(duì)象頭和棧幀中的鎖記錄里存儲(chǔ)鎖偏向的線(xiàn)程ID,以后該線(xiàn)程在進(jìn)入和退出同步塊時(shí)不需要進(jìn)行CAS操作來(lái)加鎖和解鎖终畅,只需簡(jiǎn)單地測(cè)試一下對(duì)象頭的Mark Word里是否存儲(chǔ)著指向當(dāng)前線(xiàn)程的偏向鎖籍胯。如果測(cè)試成功,表示線(xiàn)程已經(jīng)獲得了鎖离福。如果測(cè)試失敗杖狼,則需要再測(cè)試一下Mark Word中偏向鎖的標(biāo)識(shí)是否設(shè)置成了1(表示當(dāng)前是偏向鎖):如果沒(méi)有設(shè)置,則使用CAS競(jìng)爭(zhēng)鎖妖爷;如果設(shè)置了蝶涩,則嘗試使用CAS將對(duì)象頭的偏向鎖指向當(dāng)前線(xiàn)程。

5.偏向鎖使用了一種等到競(jìng)爭(zhēng)出現(xiàn)才釋放鎖的機(jī)制絮识,所以當(dāng)其他線(xiàn)程嘗試競(jìng)爭(zhēng)偏向鎖時(shí)绿聘,持有偏向鎖的線(xiàn)程才會(huì)釋放。偏向鎖的撤銷(xiāo)次舌,需要等待全局安全點(diǎn)(在這個(gè)時(shí)間點(diǎn)上沒(méi)有正在執(zhí)行了字節(jié)碼)熄攘。它會(huì)首先暫停擁有偏向鎖的線(xiàn)程,然后檢查持有偏向鎖的線(xiàn)程是否活著彼念,如果線(xiàn)程不處于活動(dòng)狀態(tài)挪圾,則將對(duì)象頭設(shè)置成無(wú)鎖狀態(tài);如果線(xiàn)程仍然活著逐沙,擁有偏向鎖的棧會(huì)被執(zhí)行哲思,遍歷偏向?qū)ο蟮逆i記錄,棧中的鎖記錄和對(duì)象頭的Mark Word要么重新偏向于其他線(xiàn)程吩案,要么恢復(fù)到無(wú)鎖或者標(biāo)記對(duì)象不適合作為偏向鎖也殖,最后喚醒暫停的線(xiàn)程。

6.因?yàn)樽孕龝?huì)消耗CPU务热,為了避免無(wú)用的自旋(比如獲得鎖的線(xiàn)程被阻塞住了)忆嗜,一旦鎖升級(jí)成重量級(jí)鎖,就不會(huì)再恢復(fù)到輕量級(jí)鎖狀態(tài)崎岂。當(dāng)鎖處于這個(gè)狀態(tài)下捆毫,其他線(xiàn)程試圖獲取鎖時(shí),都會(huì)被阻塞住冲甘,當(dāng)持有鎖的線(xiàn)程釋放鎖之后會(huì)喚醒這些線(xiàn)程绩卤,被喚醒的線(xiàn)程會(huì)進(jìn)行新一輪的奪鎖之爭(zhēng)途样。

7.原子操作意為“不可被中斷的一個(gè)或一系列操作”。

8.術(shù)語(yǔ)定義: 緩存行(Cache line):緩存的最小操作單位濒憋; 比較并交換(Compare and Swap, CAS):CAS操作需要輸入兩個(gè)數(shù)值何暇,一個(gè)舊值(期望操作前的值)和一個(gè)新值,在操作期間先比較舊值有沒(méi)有發(fā)生變化凛驮,如果沒(méi)有發(fā)生變化裆站,才交換成新值,發(fā)生了變化則不交換黔夭; CPU流水線(xiàn)(CPU pipeline):CPU流水線(xiàn)的工作方式就像工業(yè)生產(chǎn)上的裝配流水線(xiàn)宏胯,在CPU中由56個(gè)不同功能的電路單元組成一條指令處理流水線(xiàn),然后將一條X86指令分成56步后再由這些電路單元分別執(zhí)行本姥,這樣就能實(shí)現(xiàn)在一個(gè)CPU時(shí)鐘周期完成一條指令肩袍,因此提高CPU的運(yùn)算速度。 內(nèi)存順序沖突(Memory order violation):內(nèi)存順序沖突一般是由假共享引起的婚惫,假共享是指多個(gè)CPU同時(shí)修改同一個(gè)緩存行的不同部分而引起其中一個(gè)CPU的操作無(wú)效氛赐,當(dāng)出現(xiàn)這個(gè)內(nèi)存順序沖突時(shí),CPU必須清空流水線(xiàn)先舷。

9.處理器實(shí)現(xiàn)原子操作的方式:

  • 通過(guò)總線(xiàn)鎖保證原子性鹰祸。總線(xiàn)鎖就是使用處理器提供的一個(gè)LOCK #信號(hào)密浑,當(dāng)一個(gè)處理器在總線(xiàn)上輸出此信號(hào)時(shí)蛙婴,其他處理器的請(qǐng)求將被阻塞,那么該處理器可以獨(dú)占共享內(nèi)存尔破。
  • 通過(guò)緩存鎖定來(lái)保證原子性街图。頻繁使用的內(nèi)存會(huì)緩存再處理器的L1、L2和L3高速緩存里懒构,那么原子操作就可以直接在處理器內(nèi)部緩存中進(jìn)行餐济,并不需要聲明總線(xiàn)鎖。所謂“緩存鎖定”是指內(nèi)存區(qū)域如果被緩存再處理器的緩存行中胆剧,并且在Lock操作期間被鎖定絮姆,那么當(dāng)它執(zhí)行鎖操作會(huì)寫(xiě)到內(nèi)存時(shí),處理器不在總線(xiàn)上聲言LOCK #信號(hào)秩霍,而是修改內(nèi)部?jī)?nèi)存地址篙悯,并允許它的緩存一致性機(jī)制來(lái)保證操作的原子性,因?yàn)榫彺嬉恢滦詸C(jī)制會(huì)阻止同時(shí)修改由兩個(gè)以上處理器緩存的內(nèi)存區(qū)域數(shù)據(jù)铃绒,當(dāng)其他處理器回寫(xiě)已被鎖定的緩存行的數(shù)據(jù)時(shí)鸽照,會(huì)使緩存行無(wú)效。

10.如果一個(gè)操作執(zhí)行的結(jié)果需要對(duì)另一個(gè)操作可見(jiàn)颠悬,那么兩個(gè)操作之間必須要存在happens-before關(guān)系矮燎。

11.happens-before規(guī)則如下:

  • 程序順序規(guī)則:一個(gè)線(xiàn)程中的每個(gè)操作定血,happens-before于該線(xiàn)程中的任意后續(xù)操作;
  • 監(jiān)視器鎖規(guī)則:對(duì)一個(gè)鎖的解鎖诞外,happens-before于隨后對(duì)這個(gè)鎖的加鎖澜沟;
  • volatile變量規(guī)則:對(duì)一個(gè)volatile變量的寫(xiě),happens-before于任意后續(xù)對(duì)這個(gè)volatile變量的讀峡谊;
  • 傳遞性:如果A happens-before B茫虽,B happens-before C,那么A happens-before C靖苇;

12.happens-before僅僅要求前一個(gè)操作(執(zhí)行的結(jié)果)對(duì)后一個(gè)操作可見(jiàn)席噩,且前一個(gè)操作按順序排在第二個(gè)操作之前班缰。

13.重排序:重排序是指編譯器和處理器為了優(yōu)化程序性能而對(duì)指令序列而進(jìn)行重新排序的一種手段贤壁。

14.編譯器和處理器會(huì)對(duì)操作進(jìn)行重排序,編譯器和處理在重排序時(shí)埠忘,會(huì)遵守?cái)?shù)據(jù)依賴(lài)性脾拆,編譯器和處理器不會(huì)改變存在數(shù)據(jù)依賴(lài)關(guān)系的兩個(gè)操作的執(zhí)行順序;這里所說(shuō)的數(shù)據(jù)依賴(lài)性?xún)H針對(duì)單個(gè)處理器中執(zhí)行的指令序列和單個(gè)線(xiàn)程中執(zhí)行的操作莹妒,不同處理器之間和不同線(xiàn)程之間的數(shù)據(jù)依賴(lài)性不被編譯器和處理器考慮名船。

15.as-if-serial語(yǔ)義的意思是:不管怎么重排序(編譯器和處理器為了提高并行度),(單線(xiàn)程)程序的執(zhí)行結(jié)果不能被改變旨怠,編譯器渠驼,runtime和處理器都必須遵守as-if-serial語(yǔ)義。

16.在計(jì)算機(jī)中鉴腻,軟件技術(shù)和硬件技術(shù)有一個(gè)共同的目標(biāo):在不改變程序執(zhí)行結(jié)果的前提下迷扇,盡可能提高并行度。

17.當(dāng)代碼中存在控制依賴(lài)性時(shí)爽哎,會(huì)影響指令序列執(zhí)行的并行度蜓席。為此,編譯器和處理器會(huì)采用猜測(cè)執(zhí)行來(lái)客戶(hù)控制相關(guān)性對(duì)并行度的影響课锌。

18.在單線(xiàn)程程序中厨内,對(duì)存在控制依賴(lài)的程序重排序,不會(huì)改變執(zhí)行結(jié)果(這也是as-if-serial語(yǔ)義允許對(duì)存在控制依賴(lài)的操作進(jìn)行重排序的原因)渺贤;但在多線(xiàn)程程序中雏胃,對(duì)存在控制依賴(lài)的操作重排序,可能會(huì)改變程序的執(zhí)行結(jié)果志鞍。

19.數(shù)據(jù)競(jìng)爭(zhēng)的定義:在一個(gè)線(xiàn)程中寫(xiě)一個(gè)變量丑掺,在另一個(gè)線(xiàn)程中讀同一個(gè)變量,而且寫(xiě)和讀沒(méi)有通過(guò)同步來(lái)排序述雾。

20.如果程序是正確同步的街州,程序的執(zhí)行將具有順序一致性--即該程序的執(zhí)行結(jié)果與程序在順序一致性模型中的執(zhí)行結(jié)果相同兼丰。

21.順序一致性?xún)?nèi)存模型的兩大特性:

  • 一個(gè)線(xiàn)程中的所有操作必須按照程序的順序來(lái)執(zhí)行;
  • (不管程序是否同步)所有線(xiàn)程都只能看到一個(gè)單一的操作執(zhí)行順序唆缴。在順序一致性?xún)?nèi)存模型中鳍征,每個(gè)操作都必須原子執(zhí)行且立刻對(duì)所有線(xiàn)程可見(jiàn)。

22.在Java內(nèi)存模型中面徽,臨界區(qū)內(nèi)的代碼可以重排序(但Java內(nèi)存模型不允許臨界區(qū)內(nèi)的代碼逸出到臨界區(qū)之外艳丛,那樣會(huì)破壞監(jiān)視器的語(yǔ)義)。Java內(nèi)存模型會(huì)在退出臨界區(qū)和進(jìn)入臨界區(qū)這兩個(gè)關(guān)鍵時(shí)間點(diǎn)做一些特殊處理趟紊,使得線(xiàn)程在這兩個(gè)時(shí)間點(diǎn)具有與順序一致性模型相同的內(nèi)存視圖氮双。

23.Java內(nèi)存模型與順序一致性模型的差別:

  • 順序一致性模型保證單線(xiàn)程內(nèi)的操作會(huì)按程序的順序執(zhí)行,而Java內(nèi)存模型不保證單線(xiàn)程內(nèi)的操作按照程序順序執(zhí)行霎匈;
  • 順序一致性模型保證所有線(xiàn)程只能看到一致的操作執(zhí)行順序戴差,而Java內(nèi)存模型不保證所有線(xiàn)程能看到一致的操作執(zhí)行順序;
  • Java內(nèi)存模型不保證對(duì)64位的long和double類(lèi)型變量寫(xiě)操作具有原子性铛嘱,而順序一致性模型保證對(duì)所有的內(nèi)存讀寫(xiě)操作都具有原子性暖释。

24.64位long和double類(lèi)型變量的寫(xiě)操作不具有原子性的原因是:在一些32位的機(jī)器上,對(duì)于內(nèi)存的寫(xiě)入操作墨吓,每次只能是原子的執(zhí)行一段32位內(nèi)存的寫(xiě)入球匕,對(duì)于64位的變量,需要分兩次原子的寫(xiě)入操作進(jìn)行帖烘,因而整體來(lái)說(shuō)是不具備原子性的亮曹。

25.在jdk1.5版本以前,一個(gè)64位long/double類(lèi)型變量的讀/寫(xiě)操作可以拆分為兩個(gè)32位的讀/寫(xiě)操作來(lái)進(jìn)行秘症;在jdk1.5版本(含)之后照卦,64位的long/double類(lèi)型變量的寫(xiě)入操作能夠拆分為兩個(gè)32位的寫(xiě)操作來(lái)進(jìn)行,而讀操作則通過(guò)jvm保證其具有原子性历极。

26.volatile變量的特性:

  • 可見(jiàn)性窄瘟。一個(gè)volatile變量的讀,總是能夠看到最后一個(gè)線(xiàn)程對(duì)volatile變量寫(xiě)入的值趟卸;
  • 原子性蹄葱。對(duì)任意單個(gè)volatile變量的讀/寫(xiě)具有原子性,但是類(lèi)似于volatile++這種復(fù)合操作不具備原子性锄列。

27.當(dāng)讀一個(gè)volatile變量時(shí)图云,Java內(nèi)存模型會(huì)把該線(xiàn)程對(duì)應(yīng)的本地內(nèi)存置為無(wú)效,而從主內(nèi)存中讀取共享變量邻邮。

28.volatile寫(xiě)和volatile讀的內(nèi)存語(yǔ)義:

  • 線(xiàn)程A寫(xiě)一個(gè)volatile變量竣况,實(shí)質(zhì)上是線(xiàn)程A向接下來(lái)所要讀這個(gè)volatile變量的線(xiàn)程發(fā)出了(其對(duì)共享變量所作修改的)信息;
  • 線(xiàn)程B讀一個(gè)volatile變量筒严,實(shí)質(zhì)上是線(xiàn)程B接收了之前某個(gè)線(xiàn)程發(fā)出的(在寫(xiě)這個(gè)volatile變量之前對(duì)共享變量所做修改的)信息丹泉;
  • 線(xiàn)程A寫(xiě)一個(gè)volatile變量情萤,隨后線(xiàn)程B讀一個(gè)volatile變量,這個(gè)過(guò)程實(shí)質(zhì)上是線(xiàn)程A通過(guò)主內(nèi)存向線(xiàn)程B發(fā)送消息摹恨。

29.volatile變量讀寫(xiě)操作重排序的規(guī)則:

  • 當(dāng)?shù)诙€(gè)操作是volatile寫(xiě)時(shí)筋岛,不管第一個(gè)操作是什么,都不能重排序晒哄。這個(gè)規(guī)則確保volatile寫(xiě)之前的操作不會(huì)被重排序到volatile寫(xiě)之后睁宰。
  • 當(dāng)?shù)谝粋€(gè)操作是volatile讀時(shí),不管第二個(gè)操作是什么寝凌,都不能重排序柒傻。這個(gè)規(guī)則確保volatile讀之后的操作不會(huì)被重排序到volatile讀之前。
  • 當(dāng)?shù)谝粋€(gè)操作是volatile寫(xiě)较木,第二個(gè)操作是volatile讀時(shí)红符,不能重排序。

30.Java內(nèi)存模型對(duì)于volatile變量插入內(nèi)存屏障的策略:

  • 在每個(gè)volatile寫(xiě)操作之前插入一個(gè)StoreStore屏障劫映;
  • 在每個(gè)volatile寫(xiě)操作后面插入一個(gè)StoreLoad屏障违孝;
  • 在每個(gè)volatile讀操作后面插入一個(gè)LoadLoad屏障刹前;
  • 在每個(gè)volatile讀操作后面插入一個(gè)LoadStore屏障泳赋;

31.final域的重排序規(guī)則:

  • 在構(gòu)造函數(shù)中對(duì)一個(gè)final域的寫(xiě)入,與隨后把這個(gè)被構(gòu)造對(duì)象的引用賦值給一個(gè)引用變量喇喉,這兩個(gè)操作之間不能重排序祖今;
  • 初次讀一個(gè)包含final域的對(duì)象的引用,與隨后初次讀這個(gè)final域拣技,這兩個(gè)操作之間不能重排序千诬。

32.通過(guò)為final域增加寫(xiě)和讀重排序規(guī)則,可以為Java程序員提供初始化安全保證:只要對(duì)象是正確構(gòu)造的(被構(gòu)造對(duì)象的引用在對(duì)象構(gòu)造過(guò)程中沒(méi)有逸出)膏斤,那么不需要使用同步(指lock和volatile的使用)就可以保證任意線(xiàn)程都可以看到這個(gè)final域在構(gòu)造函數(shù)中被初始化之后的值徐绑。

33.對(duì)于會(huì)改變程序執(zhí)行結(jié)果的重排序,Java內(nèi)存模型要求編譯器和處理器必須禁止這種重排序莫辨;對(duì)于不會(huì)改變程序執(zhí)行結(jié)果的重排序傲茄,Java內(nèi)存模型對(duì)編譯器和處理器不做要求(Java內(nèi)存模型允許這種重排序)。

34.Java內(nèi)存模型對(duì)編譯器和處理器已經(jīng)盡可能少沮榜。從上面的分析可以看出盘榨,Java內(nèi)存模型其實(shí)是在遵循一個(gè)基本原則:只要不改變程序的執(zhí)行結(jié)果(指的是單線(xiàn)程程序和正確同步的多線(xiàn)程程序),編譯器和處理器怎么優(yōu)化都行蟆融。

35.如果一個(gè)操作happens-before另一個(gè)操作草巡,那么第一個(gè)操作的執(zhí)行結(jié)果將對(duì)第二個(gè)操作可見(jiàn),而且第一個(gè)操作的執(zhí)行順序排在第二個(gè)操作之前型酥;兩個(gè)操作之間存在happens-before關(guān)系山憨,并不意味著Java平臺(tái)的具體實(shí)現(xiàn)必須按照happens-before關(guān)系指定的順序來(lái)執(zhí)行查乒。如果重排序之后的執(zhí)行結(jié)果,與按happens-before關(guān)系來(lái)執(zhí)行的結(jié)果一致郁竟,那么這種重排序并不非法(也就是說(shuō)Java內(nèi)存模型允許這種重排序)侣颂。

36.jsr-133中定義的happens-before規(guī)則:

  • 程序順序規(guī)則:一個(gè)線(xiàn)程中的每個(gè)操作,happens-before于該線(xiàn)程中的任意后續(xù)操作枪孩;
  • 監(jiān)視器鎖規(guī)則:對(duì)一個(gè)鎖的解鎖憔晒,happens-before于后續(xù)對(duì)該鎖的加鎖;
  • volatile變量規(guī)則:對(duì)一個(gè)volatile域的寫(xiě)蔑舞,happens-before于任意后續(xù)對(duì)這個(gè)volatile域的讀拒担;
  • 傳遞性:如果A happens-before B,且B happens-before C攻询,那么A happens-before C从撼;
  • start規(guī)則:如果線(xiàn)程A執(zhí)行操作ThreadB.start()(啟動(dòng)線(xiàn)程B),那么A線(xiàn)程中的ThreadB.start()操作happens-before于線(xiàn)程B中的任意操作钧栖;
  • join規(guī)則:如果線(xiàn)程A執(zhí)行ThreadB.join()并成功返回低零,那么線(xiàn)程B中的任意操作happens-before于線(xiàn)程A從ThreadB.join()操作成功返回。

37.當(dāng)一個(gè)Java虛擬機(jī)中不存在非Daemon線(xiàn)程的時(shí)候拯杠,Java虛擬機(jī)將會(huì)退出掏婶。

38.Daemon屬性需要在啟動(dòng)線(xiàn)程之前設(shè)置,不能再啟動(dòng)線(xiàn)程之后設(shè)置潭陪。

39.Daemon線(xiàn)程被用作完成支持性工作雄妥,但是在Java虛擬機(jī)退出時(shí)Daemon線(xiàn)程中的finally塊并不一定會(huì)執(zhí)行,因而在構(gòu)建Daemon線(xiàn)程時(shí)依溯,不能依靠finally塊中的內(nèi)容來(lái)確保執(zhí)行關(guān)閉或清理資源的邏輯老厌。

40.線(xiàn)程start()方法的含義是:當(dāng)前線(xiàn)程(即parent線(xiàn)程)同步告知Java虛擬機(jī),只要線(xiàn)程規(guī)劃器空閑黎炉,應(yīng)立即啟動(dòng)調(diào)用start()方法的線(xiàn)程枝秤。

41.在啟動(dòng)一個(gè)線(xiàn)程時(shí),最好為這個(gè)線(xiàn)程設(shè)置一個(gè)名稱(chēng)慷嗜,這樣在進(jìn)行jstack分析時(shí)可方便問(wèn)題排查淀弹。

42.調(diào)用wait()、notify()和notifyAll()需要注意的細(xì)節(jié):

  • 使用wait()洪添、notify()和notifyAll()時(shí)需要對(duì)調(diào)用對(duì)象加鎖垦页;
  • 調(diào)用wait()方法后,線(xiàn)程狀態(tài)由RUNNING變成WAITING干奢,并將當(dāng)前線(xiàn)程放置到對(duì)象的等待隊(duì)列痊焊;
  • notify()和notifyAll()調(diào)用之后,線(xiàn)程依舊不會(huì)從wait()返回,需要調(diào)用notify()或notifyAll()的線(xiàn)程釋放鎖之后薄啥,等待線(xiàn)程才有機(jī)會(huì)從wait()返回辕羽;
  • notify()將等待隊(duì)列中的一個(gè)線(xiàn)程從等待隊(duì)列移到同步隊(duì)列中,而notifyAll()則是將等待隊(duì)列中所有線(xiàn)程從等待隊(duì)列移到同步隊(duì)列中垄惧,被移動(dòng)的線(xiàn)程狀態(tài)由WAITING變?yōu)锽LOCKED刁愿;
  • 從wait()方法返回的前提是獲得了調(diào)用對(duì)象的鎖。

43.Wait Notify的經(jīng)典范式: ①等待方遵循如下規(guī)則:

  • 獲取對(duì)象的鎖到逊;
  • 如果條件不滿(mǎn)足铣口,那么調(diào)用對(duì)象的wait()方法,被通知后仍要檢查條件觉壶;
  • 條件滿(mǎn)足則執(zhí)行對(duì)應(yīng)的邏輯脑题; 對(duì)應(yīng)偽代碼如下:
synchronized (對(duì)象) {
    while (條件不滿(mǎn)足) {
        對(duì)象.wait();        
    }
    對(duì)象的處理邏輯
}

②通知方遵循如下原則:

  • 獲得對(duì)象的鎖;
  • 改變條件铜靶;
  • 通知所有等待在對(duì)象上的線(xiàn)程叔遂; 對(duì)應(yīng)偽代碼如下:
synchronized (對(duì)象) {
    改變條件;
    對(duì)象.notifyAll();
}

44.等待超時(shí)模式的偽代碼:

public synchronized Object get(long mills) throws InterruptedException {
    long future = System.currentTimeMillis() + mills;
    long remaining = mills;

    // 當(dāng)超時(shí)大于0并且result返回值不滿(mǎn)足要求
    while ((result == null) && remaining > 0) {
        wait(remaining);
        remaining = future - System.currentTimeMillis();
    }

    return result;
}

45.如果在絕對(duì)時(shí)間上,先對(duì)鎖進(jìn)行獲取的請(qǐng)求一定先被滿(mǎn)足争剿,那么這個(gè)鎖是公平的已艰,反之,是不公平的蚕苇。事實(shí)上哩掺,公平鎖的效率沒(méi)有非公平鎖的效率高,但是公平鎖能夠減少“饑餓”發(fā)生的概率捆蜀。

46.實(shí)現(xiàn)鎖的重進(jìn)入需要解決的問(wèn)題:

  • 線(xiàn)程再次獲取鎖疮丛。鎖需要去識(shí)別獲取鎖的線(xiàn)程是否為當(dāng)前占據(jù)鎖的線(xiàn)程幔嫂,如果是辆它,則再次成功獲取履恩;
  • 鎖的最終釋放锰茉。線(xiàn)程重復(fù)n此獲取了鎖,隨后在第n此釋放該鎖后切心,其他線(xiàn)程能夠獲取到該鎖飒筑。鎖的最終釋放要求鎖對(duì)于獲取進(jìn)行計(jì)數(shù)自增,計(jì)數(shù)表示當(dāng)前鎖被重復(fù)獲取的次數(shù)绽昏,而鎖被釋放時(shí)协屡,計(jì)數(shù)自減,當(dāng)計(jì)數(shù)等于0時(shí)全谤,表示鎖已經(jīng)成功釋放肤晓。

47.讀寫(xiě)鎖在同一時(shí)刻可以允許多個(gè)線(xiàn)程訪問(wèn),但是在寫(xiě)線(xiàn)程訪問(wèn)時(shí),所有的讀線(xiàn)程和其他寫(xiě)線(xiàn)程均被阻塞补憾。讀寫(xiě)鎖維護(hù)了一對(duì)鎖:一個(gè)讀鎖和一個(gè)寫(xiě)鎖漫萄,通過(guò)分離讀鎖和寫(xiě)鎖,使得并發(fā)性相比一般的排他鎖有了很大提升盈匾。

48.讀寫(xiě)鎖將變量切分成了兩個(gè)部分腾务,高16位表示讀,低16位表示寫(xiě)削饵。

49.ReentrantReadWriteLock使用位來(lái)表征讀寫(xiě)鎖狀態(tài)的方式:假設(shè)當(dāng)前同步狀態(tài)值為S岩瘦,寫(xiě)狀態(tài)等于S&0x0000FFFF(將高16位全部抹去),讀狀態(tài)等于S>>>16(無(wú)符號(hào)補(bǔ)0右移16位)窿撬。當(dāng)寫(xiě)狀態(tài)增加1時(shí)担钮,等于S+1,當(dāng)讀狀態(tài)增加1時(shí)尤仍,等于S+(1<<16)箫津,也就是S+0x00010000

50.根據(jù)上述狀態(tài)劃分得出一個(gè)結(jié)論:S不等于0時(shí),當(dāng)寫(xiě)狀態(tài)(S&0x0000FFFF)等于0時(shí)宰啦,則讀狀態(tài)(S>>>16)大于0苏遥,即讀鎖已被獲取。

51.對(duì)于ReentrantReadWriteLock赡模,只有等待其他讀線(xiàn)程都釋放了讀鎖田炭,寫(xiě)鎖才能被當(dāng)前線(xiàn)程獲取,而寫(xiě)鎖一旦被獲取漓柑,則其他讀寫(xiě)線(xiàn)程的后續(xù)訪問(wèn)均被阻塞教硫。

52.鎖降級(jí)指的是把持住(當(dāng)前擁有的)寫(xiě)鎖辆布,再獲取到讀鎖瞬矩,隨后釋放(先前擁有的)寫(xiě)鎖的過(guò)程。

53.LockSupport定義了一組以park開(kāi)頭的方法用來(lái)阻塞當(dāng)前線(xiàn)程锋玲,以及unpark(Thread thread)方法來(lái)喚醒一個(gè)被阻塞的線(xiàn)程景用。

54.一般都會(huì)將Condition對(duì)象作為成員變量。當(dāng)調(diào)用await()方法后惭蹂,當(dāng)前線(xiàn)程會(huì)釋放鎖并在此等待伞插,而其他線(xiàn)程調(diào)用Condition對(duì)象的signal()方法,通知當(dāng)前線(xiàn)程后盾碗,當(dāng)前線(xiàn)程才從await()方法返回媚污,并在返回前獲取到了鎖。

55.在Condition的等待隊(duì)列中并沒(méi)有使用CAS算法來(lái)保證新加入的節(jié)點(diǎn)是加入到節(jié)點(diǎn)尾部廷雅,因?yàn)檎{(diào)用Condition.await()方法的線(xiàn)程必定是獲取了鎖的線(xiàn)程耗美,其是通過(guò)鎖來(lái)保證線(xiàn)程安全的氢伟。

56.多線(xiàn)程會(huì)導(dǎo)致HashMap的Entry鏈表形成環(huán)形數(shù)據(jù)結(jié)構(gòu),一旦形成環(huán)形數(shù)據(jù)結(jié)構(gòu)幽歼,Entry的next節(jié)點(diǎn)將永不為空朵锣,就會(huì)產(chǎn)生死循環(huán)獲取Entry。

57.HashTable容器使用synchronized來(lái)保證線(xiàn)程安全甸私,當(dāng)一個(gè)線(xiàn)程訪問(wèn)HashTable的同步方法時(shí)诚些,其他線(xiàn)程訪問(wèn)HashTable的任何方法都將進(jìn)入阻塞或輪詢(xún)狀態(tài)。

58.ConcurrentHashMap容器中有多把鎖皇型,每一把鎖只鎖定一部分?jǐn)?shù)據(jù)诬烹,多線(xiàn)程訪問(wèn)時(shí),對(duì)于不同段數(shù)據(jù)的訪問(wèn)不需要競(jìng)爭(zhēng)同一把鎖弃鸦,從而可以有效的提高并發(fā)訪問(wèn)效率绞吁,這就是ConcurrentHashMap的鎖分段技術(shù)。

59.ConcurrentHashMap在為Segament擴(kuò)容的時(shí)候唬格,首先會(huì)創(chuàng)建一個(gè)長(zhǎng)度是原來(lái)兩倍的數(shù)組家破,然后通過(guò)再散列將原數(shù)組中的數(shù)據(jù)散列到新的數(shù)組中。為了高效购岗,ConcurrentHashMap不會(huì)對(duì)Segament進(jìn)行擴(kuò)容汰聋。

60.ConcurrentHashMap計(jì)算size的方式如下:在Segament對(duì)象中有一個(gè)字段count,該字段記錄了當(dāng)前Segament中所有的鍵值對(duì)的數(shù)目喊积,在調(diào)用size()方法時(shí)通過(guò)累加每個(gè)Segament中的count烹困,從而得到總的count,但是由于在累加的過(guò)程中可能之前累加的count發(fā)生了變化乾吻,因而ConcurrentHashMap通過(guò)兩次累加每個(gè)Segament中的count髓梅,并比較兩次得到的數(shù)值是否相同,如果相同則返回绎签,否則將所有對(duì)表進(jìn)行結(jié)構(gòu)性修改的操作都鎖住枯饿,然后進(jìn)行一次累加得到結(jié)果。

61.阻塞隊(duì)列中方法說(shuō)明:
阻塞隊(duì)列方法說(shuō)明

62.各個(gè)阻塞隊(duì)列說(shuō)明: ①ArrayBlockingQueue:其是用一個(gè)數(shù)組實(shí)現(xiàn)的有界阻塞隊(duì)列辜御,按照先進(jìn)先出的方式排序鸭你; ②LinkedBlockingQueue:其是一個(gè)用鏈表實(shí)現(xiàn)的有界阻塞隊(duì)列,此隊(duì)列的默認(rèn)和最大長(zhǎng)度為Integer.MAX_VALUE擒权; ③PriorityBlockingQueue:其是一個(gè)支持優(yōu)先級(jí)的無(wú)界阻塞隊(duì)列,默認(rèn)情況下按照自然順序升序排序阁谆,如果指定了Comparator則按照指定的排序方式排序碳抄,需要注意的是其不能保證同優(yōu)先級(jí)元素的順序; ④DelayedQueue:其是一個(gè)支持延遲獲取元素的無(wú)界阻塞隊(duì)列场绿,隊(duì)列使用PriorityQueue實(shí)現(xiàn)剖效,隊(duì)列中的元素必須實(shí)現(xiàn)Delayed接口,在創(chuàng)建元素時(shí)可以指定多久才能從隊(duì)列中獲取到元素,只有延遲期滿(mǎn)時(shí)才能從隊(duì)列中提取元素璧尸; ⑤SynchronousQueue:其是一個(gè)不存儲(chǔ)元素的阻塞隊(duì)列咒林,每個(gè)put操作必須等待一個(gè)take操作,否則不能添加元素爷光,其也支持公平和非公平策略訪問(wèn)隊(duì)列(該隊(duì)列的吞吐量高于LinkedBlockingQueue和ArrayBlockingQueue)垫竞; ⑥LinkedTransferQueue:其是一個(gè)有鏈表結(jié)構(gòu)組成的無(wú)界阻塞TransferQueue隊(duì)列,相比于其他阻塞隊(duì)列蛀序,其多了tryTransfer和transfer方法欢瞪,對(duì)于transfer方法,如果當(dāng)前有正在等待的消費(fèi)者徐裸,transfer方法會(huì)將生產(chǎn)者傳入的元素立即transfer到消費(fèi)者遣鼓,如果沒(méi)有等待的消費(fèi)者,其會(huì)將元素放入到隊(duì)列的tail節(jié)點(diǎn)重贺,對(duì)于tryTransfer方法骑祟,其是用來(lái)試探生產(chǎn)者傳入的元素能否直接傳給消費(fèi)者,如果有則返回true气笙,否則返回false曾我,對(duì)于有時(shí)間限的tryTransfer方法,如果有正在等待的消費(fèi)者健民,該方法直接返回true抒巢,如果沒(méi)有,則等待設(shè)定的時(shí)間秉犹,還是沒(méi)有則返回false蛉谜; ⑦LinkedBlockingDeque:其是一個(gè)由鏈表結(jié)構(gòu)組成的雙向阻塞隊(duì)列,即可以從隊(duì)列頭和隊(duì)列尾兩端插入和移除元素崇堵,雙向隊(duì)列多了一個(gè)隊(duì)列入隊(duì)和出隊(duì)的口型诚,因而在多線(xiàn)程入隊(duì)和出隊(duì)時(shí)也就減少了一半的競(jìng)爭(zhēng)。

63.DelayedQueue的兩個(gè)應(yīng)用場(chǎng)景: ①緩存系統(tǒng)的設(shè)計(jì):可以用DelayedQueue設(shè)計(jì)緩存系統(tǒng)鸳劳,將元素放置到DelayedQueue中后狰贯,如果在指定時(shí)間之后能從DelayedQueue中獲取到元素,那么說(shuō)明元素過(guò)期了赏廓; ②定時(shí)任務(wù)調(diào)度:可以將一些定時(shí)任務(wù)放到DelayedQueue中涵紊,通過(guò)一個(gè)線(xiàn)程輪詢(xún)隊(duì)列,當(dāng)從隊(duì)列中取到元素之后則執(zhí)行該任務(wù)幔摸。

64.實(shí)現(xiàn)Delayed接口的方式(分三步): ①在創(chuàng)建對(duì)象時(shí)摸柄,初始化基本數(shù)據(jù),使用time記錄當(dāng)前對(duì)象延遲到什么時(shí)候使用既忆,使用sequenceNumber來(lái)標(biāo)識(shí)元素在隊(duì)列中的先后順序驱负; ②實(shí)現(xiàn)getDelay方法嗦玖,該方法返回當(dāng)前元素還需要延時(shí)多長(zhǎng)時(shí)間,單位是納秒跃脊; ③實(shí)現(xiàn)compareTo方法來(lái)指定元素的順序宇挫,讓延時(shí)時(shí)間最長(zhǎng)的放在隊(duì)列的末尾。

65.park方法會(huì)阻塞當(dāng)前線(xiàn)程酪术,其在以下四種情況下會(huì)返回:

  • 與park對(duì)應(yīng)的unpark方法執(zhí)行或已經(jīng)執(zhí)行器瘪,“已經(jīng)執(zhí)行”是指unpark先執(zhí)行,然后執(zhí)行park方法拼缝;
  • 線(xiàn)程被中斷娱局;
  • 等待完time參數(shù)指定的毫秒數(shù);
  • 異尺制撸現(xiàn)象發(fā)生時(shí)衰齐,這個(gè)異常現(xiàn)象沒(méi)有任何原因继阻。

66.Fork/Join框架是一個(gè)把大任務(wù)分隔成若干個(gè)小任務(wù)耻涛,最終匯總每個(gè)小任務(wù)結(jié)果后得到大任務(wù)結(jié)果的框架。

67.工作竊取算法:工作竊取算法是指某個(gè)線(xiàn)程從其他隊(duì)列里竊取任務(wù)來(lái)執(zhí)行瘟檩,為了減少與正常執(zhí)行線(xiàn)程之間的競(jìng)爭(zhēng)抹缕,其一般是使用雙端隊(duì)列來(lái)完成。在Fork/Join框架中墨辛,一般fork出來(lái)的子任務(wù)是放在不同的隊(duì)列中的卓研,并且每個(gè)隊(duì)列有一個(gè)線(xiàn)程執(zhí)行其中的任務(wù),如果某個(gè)線(xiàn)程執(zhí)行得較快睹簇,任務(wù)已做完奏赘,其不能一直等待著其他的隊(duì)列線(xiàn)程執(zhí)行完任務(wù)之后才合并結(jié)果,因而需要使用工作竊取算法使其同步執(zhí)行其他隊(duì)列的任務(wù)太惠。

68.工作竊取算法的優(yōu)點(diǎn):充分利用線(xiàn)程進(jìn)行并行計(jì)算磨淌,減少線(xiàn)程間的競(jìng)爭(zhēng);缺點(diǎn):在某些情況下還是存在競(jìng)爭(zhēng)凿渊,比如雙端隊(duì)列只有一個(gè)任務(wù)時(shí)梁只。并且該算法消耗了更多的系統(tǒng)資源,比如創(chuàng)建了多個(gè)線(xiàn)程和多個(gè)雙端隊(duì)列埃脏。

69.Fork/Join框架的設(shè)計(jì):

  • 步驟一:分割任務(wù)搪锣。首先需要一個(gè)fork類(lèi)來(lái)吧大任務(wù)分割成子任務(wù),有可能子任務(wù)還是很大剂癌,所以還需要不停的分割淤翔,直到分割出的子任務(wù)足夠畜鲜病董饰;
  • 步驟二:執(zhí)行任務(wù)并合并結(jié)果:分割的子任務(wù)分別放在雙端隊(duì)列里,然后幾個(gè)啟動(dòng)線(xiàn)程分別從雙端隊(duì)列里獲取任務(wù)執(zhí)行侈贷。子任務(wù)執(zhí)行完的結(jié)果統(tǒng)一放在一個(gè)隊(duì)列里谐檀,啟動(dòng)一個(gè)線(xiàn)程從隊(duì)列里拿數(shù)據(jù)抡谐,然后合并這些數(shù)據(jù)。

70.Fork/Join框架的主要類(lèi):

  • ForkJoinTask:該類(lèi)表示要執(zhí)行的任務(wù)桐猬,使用時(shí)我們主要繼承其兩個(gè)子類(lèi):RecursiveAction和RecursiveTask麦撵。RecursiveAction表示沒(méi)有返回值的任務(wù),RecursiveTask表示有返回值的任務(wù)溃肪;
  • ForkJoinPool:執(zhí)行ForkJoinTask的類(lèi)免胃。

71.ForkJoinTask在執(zhí)行時(shí),如果拋出異常惫撰,那么主線(xiàn)程是無(wú)法捕獲到該異常的羔沙,因而該類(lèi)提供了一個(gè)isCompletedAbnormally方法,用于檢測(cè)是否正常完成厨钻,并且提供了一個(gè)getException方法扼雏,如果當(dāng)前任務(wù)被取消了,那么該方法將返回CancellationException夯膀,如果任務(wù)沒(méi)有完成或拋出異常诗充,則返回null。

72.AtomicIntegerArray的構(gòu)造函數(shù)可以傳入一個(gè)整形數(shù)組诱建,也可以傳入一個(gè)length蝴蜓,其會(huì)在內(nèi)部將傳入的數(shù)組復(fù)制一份或者新建一個(gè)length長(zhǎng)度的數(shù)組,因而對(duì)AtomicIntegerArray的操作不會(huì)影響原數(shù)組的值俺猿。

73.原子更新字段類(lèi)AtomicIntegerFieldUpdater茎匠、AtomicLongFieldUpdater、AtomicStampedReference使用時(shí)需要注意兩點(diǎn):

  • 因?yàn)樵痈伦侄晤?lèi)都是抽象類(lèi)辜荠,每次使用的時(shí)候必須使用靜態(tài)方法newUpdater()創(chuàng)建一個(gè)更新器汽抚,并且需要設(shè)置想要更新的類(lèi)和屬性;
  • 更新類(lèi)的字段(屬性)必須使用public volatile修飾符伯病。

74.AtomicStampedReference是原子更新帶有版本號(hào)的引用類(lèi)型造烁,該類(lèi)將整數(shù)值與引用關(guān)聯(lián)起來(lái),更新引用的時(shí)候也會(huì)原子的更新版本號(hào)午笛,從而解決了使用CAS進(jìn)行原子更新時(shí)可能出現(xiàn)的ABA問(wèn)題惭蟋。

75.CountDownLatch允許一個(gè)或多個(gè)線(xiàn)程等待其他線(xiàn)程完成任務(wù)之后才會(huì)繼續(xù)往下執(zhí)行,其內(nèi)部維護(hù)了一個(gè)整數(shù)變量药磺,每次調(diào)用countDown()方法告组,該整數(shù)變量都會(huì)減一,而另外的調(diào)用await()方法的線(xiàn)程將會(huì)被阻塞癌佩,直到多次調(diào)用countDown()方法后內(nèi)部維護(hù)的整數(shù)變量值減為0了木缝。

76.CountDownLatch在構(gòu)造時(shí)需要傳入一個(gè)整數(shù)便锨,每次調(diào)用該類(lèi)對(duì)象的countDown()方法時(shí)內(nèi)部維護(hù)的該整數(shù)就會(huì)減一,而CountDownLatch::await()方法會(huì)阻塞當(dāng)前線(xiàn)程我碟,直到其內(nèi)部維護(hù)的整數(shù)值降為0放案。這里countDown()方法的調(diào)用可以是一個(gè)線(xiàn)程調(diào)用多次,也可以是多個(gè)線(xiàn)程每個(gè)調(diào)用一次矫俺,只要調(diào)用該整數(shù)值次即可吱殉。

77.CountDownLatch構(gòu)造函數(shù)傳入的整數(shù)值必須大于等于0.

78.CyclicBarrier的作用是讓一組線(xiàn)程到達(dá)一個(gè)屏障(也可以說(shuō)是一個(gè)同步點(diǎn))時(shí)阻塞,直到所有的線(xiàn)程都到達(dá)了該屏障厘托,然后才讓所有線(xiàn)程繼續(xù)往下執(zhí)行友雳。

79.CyclicBarrier另外提供了一個(gè)如下構(gòu)造函數(shù)CyclicBarrier(int parties, Runnable barrier-action),第一個(gè)參數(shù)還是指將要阻塞的線(xiàn)程數(shù)量铅匹,而第二個(gè)參數(shù)指定了一個(gè)任務(wù)押赊,該任務(wù)會(huì)由第一個(gè)到達(dá)屏障的線(xiàn)程執(zhí)行,但是其是在所有阻塞的線(xiàn)程執(zhí)行當(dāng)前任務(wù)到達(dá)屏障之后準(zhǔn)備繼續(xù)執(zhí)行后續(xù)任務(wù)時(shí)才執(zhí)行伊群,也即所有阻塞的線(xiàn)程從await()方法中返回的時(shí)候考杉。

80.Semaphore(信號(hào)量)是用來(lái)控制同時(shí)訪問(wèn)特定資源的線(xiàn)程數(shù)量,它通過(guò)協(xié)調(diào)各個(gè)線(xiàn)程舰始,以保證合理的使用公共資源崇棠。

81.線(xiàn)程池的優(yōu)點(diǎn):

  • 降低資源消耗。通過(guò)重復(fù)利用已創(chuàng)建的線(xiàn)程降低線(xiàn)程創(chuàng)建和銷(xiāo)毀造成的消耗丸卷;
  • 提高響應(yīng)速度枕稀。當(dāng)任務(wù)到達(dá)時(shí),任務(wù)可以部需要等到線(xiàn)程創(chuàng)建就能立即執(zhí)行谜嫉;
  • 提高線(xiàn)程的可管理性萎坷。線(xiàn)程是稀缺資源,如果無(wú)限制的創(chuàng)建沐兰,不僅會(huì)消耗系統(tǒng)資源哆档,還會(huì)降低系統(tǒng)的穩(wěn)定性,使用線(xiàn)程池可以進(jìn)行統(tǒng)一分配住闯、調(diào)優(yōu)和監(jiān)控瓜浸。

82.提交任務(wù)時(shí)線(xiàn)程池的處理流程如下: ①線(xiàn)程池判斷核心線(xiàn)程池里的線(xiàn)程是否都在執(zhí)行任務(wù)。如果不是比原,則創(chuàng)建一個(gè)新的線(xiàn)程來(lái)執(zhí)行任務(wù)插佛,如果核心線(xiàn)程池里的線(xiàn)程都在執(zhí)行任務(wù),則進(jìn)入下一個(gè)流程量窘; ②線(xiàn)程池判斷工作隊(duì)列是否已滿(mǎn)雇寇。如果工作隊(duì)列沒(méi)有滿(mǎn),則將新提交的任務(wù)存儲(chǔ)在這個(gè)工作隊(duì)列里,如果工作隊(duì)列滿(mǎn)了锨侯,則進(jìn)入下一個(gè)流程嫩海; ③線(xiàn)程池判斷線(xiàn)程池的線(xiàn)程是否都處于工作狀態(tài),如果沒(méi)有识腿,則創(chuàng)建一個(gè)新的線(xiàn)程來(lái)執(zhí)行任務(wù)出革。如果已經(jīng)滿(mǎn)了造壮,則交給飽和策略來(lái)處理這個(gè)任務(wù)渡讼。

83.CachedThreadPool是大小無(wú)界的線(xiàn)程池,適用于執(zhí)行很多的短期異步任務(wù)的小程序耳璧,或者是負(fù)載較輕的服務(wù)器成箫。

84.FixedThreadPool適用于為了滿(mǎn)足資源管理的需求,而需要限制當(dāng)前線(xiàn)程數(shù)量的應(yīng)用場(chǎng)景旨枯,它適用于負(fù)載比較重的服務(wù)器蹬昌。

85.SingleThreadExecutor適用于需要保證順序執(zhí)行各個(gè)任務(wù),并且在任意時(shí)間點(diǎn)攀隔,不會(huì)有多個(gè)線(xiàn)程是活動(dòng)的應(yīng)用場(chǎng)景皂贩。

86.使用無(wú)界隊(duì)列對(duì)FixedThreadPool帶來(lái)了如下影響:

  • 當(dāng)線(xiàn)程池中的線(xiàn)程達(dá)到corePoolSize之后,新任務(wù)將在無(wú)界隊(duì)列中等待昆汹,因此線(xiàn)程池中的線(xiàn)程數(shù)不會(huì)超過(guò)corePoolSize明刷,因而設(shè)置的maximumPoolSize將是一個(gè)無(wú)效參數(shù);
  • 由于任務(wù)會(huì)一直添加到無(wú)界隊(duì)列中满粗,并且除了corePoolSize個(gè)線(xiàn)程之后不會(huì)創(chuàng)建新的線(xiàn)程辈末,因而設(shè)置的keepAliveTime和RejectedExecutionHandler將不會(huì)產(chǎn)生影響。

87.CachedThreadPool底層是創(chuàng)建了一個(gè)ThreadPoolExecutor映皆,其corePoolSize傳入的是0挤聘,maxPoolSize是Integer.MAX_VALUE,空閑等待時(shí)間是60s捅彻,并且其使用的SynchronousQueue來(lái)處理任務(wù)组去。這里SynchronousQueue內(nèi)部是沒(méi)有容量保存任何任務(wù)的,每個(gè)線(xiàn)程提交了一個(gè)任務(wù)之后必須有一個(gè)線(xiàn)程取出任務(wù)步淹。從這些參數(shù)可以看出从隆,初始狀態(tài)下CachedThreadPool中是沒(méi)有任何線(xiàn)程的,當(dāng)提交一個(gè)新的任務(wù)之后如果當(dāng)前有空閑的線(xiàn)程贤旷,則該線(xiàn)程取出任務(wù)執(zhí)行广料,如果沒(méi)有線(xiàn)程空閑,那么就會(huì)創(chuàng)建一個(gè)新的線(xiàn)程幼驶,也就是說(shuō)如果需要執(zhí)行的任務(wù)非常多艾杏,那么創(chuàng)建的線(xiàn)程數(shù)將會(huì)急劇上升。因而CachedThreadPool適用于多任務(wù)數(shù)盅藻,并且執(zhí)行時(shí)間較短的場(chǎng)景购桑。

88.FutureTask表示一個(gè)將要執(zhí)行的任務(wù)畅铭,其不僅實(shí)現(xiàn)了Future接口,還實(shí)現(xiàn)了Runnable接口勃蜘,因而可以將其當(dāng)做一個(gè)任務(wù)提交給Executor執(zhí)行硕噩。FutureTask的任務(wù)有三種狀態(tài):未啟動(dòng)、已啟動(dòng)和已完成缭贡。對(duì)于已完成狀態(tài)炉擅,其可能有三種狀態(tài):FutureTask::run()方法正常結(jié)束,run()方法被取消而結(jié)束阳惹,run()方法拋出異常結(jié)束谍失。

89.當(dāng)FutureTask處于未啟動(dòng)或已啟動(dòng)狀態(tài)時(shí),F(xiàn)utureTask::get()方法將導(dǎo)致線(xiàn)程阻塞莹汤;當(dāng)FutureTask處于已完成狀態(tài)時(shí)快鱼,F(xiàn)utureTask::get()方法將導(dǎo)致線(xiàn)程立即返回或拋出異常。

90.當(dāng)FutureTask處于未啟動(dòng)狀態(tài)時(shí)纲岭,F(xiàn)utureTask.cancel()方法將直接取消該任務(wù)的執(zhí)行抹竹;當(dāng)其處于已啟動(dòng)狀態(tài)時(shí),如果執(zhí)行FutureTask::cancel(true)止潮,那么將以中斷此任務(wù)執(zhí)行線(xiàn)程的方式停止任務(wù)執(zhí)行窃判,如果執(zhí)行FutureTask::cancel(false),那么其不會(huì)對(duì)正在執(zhí)行此任務(wù)的線(xiàn)程產(chǎn)生影響沽翔;當(dāng)FutureTask處于已完成狀態(tài)時(shí)兢孝,執(zhí)行FutureTask::cancel()方法將返回false。

91.在實(shí)際應(yīng)用中仅偎,如果需要繼承某個(gè)已有的類(lèi)或抽象類(lèi)跨蟹,而基于“組合優(yōu)先于繼承”的原則,我們可以在要?jiǎng)?chuàng)建的類(lèi)中聲明一個(gè)內(nèi)部類(lèi)來(lái)繼承需要繼承的類(lèi)橘沥,然后將當(dāng)前類(lèi)與內(nèi)部類(lèi)使用組合來(lái)解耦窗轩。

92.生產(chǎn)者和消費(fèi)者是通過(guò)一個(gè)容器來(lái)解決生產(chǎn)者和消費(fèi)者的強(qiáng)耦合問(wèn)題。生產(chǎn)者和消費(fèi)者彼此之間不直接通信座咆,而是通過(guò)阻塞隊(duì)列來(lái)進(jìn)行通信痢艺,所以生產(chǎn)者生產(chǎn)完數(shù)據(jù)之后不用等待消費(fèi)者處理,直接扔給阻塞隊(duì)列介陶,消費(fèi)者不找生產(chǎn)者要數(shù)據(jù)堤舒,而是直接從阻塞隊(duì)列里取,阻塞隊(duì)列就相當(dāng)于一個(gè)緩沖區(qū)哺呜,平衡了生產(chǎn)者和消費(fèi)者的處理能力舌缤。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子国撵,更是在濱河造成了極大的恐慌陵吸,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,265評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件介牙,死亡現(xiàn)場(chǎng)離奇詭異壮虫,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)环础,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門(mén)囚似,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人喳整,你說(shuō)我怎么就攤上這事谆构。” “怎么了框都?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,852評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)呵晨。 經(jīng)常有香客問(wèn)我魏保,道長(zhǎng),這世上最難降的妖魔是什么摸屠? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,408評(píng)論 1 283
  • 正文 為了忘掉前任谓罗,我火速辦了婚禮,結(jié)果婚禮上季二,老公的妹妹穿的比我還像新娘檩咱。我一直安慰自己,他們只是感情好胯舷,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布刻蚯。 她就那樣靜靜地躺著,像睡著了一般桑嘶。 火紅的嫁衣襯著肌膚如雪炊汹。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,772評(píng)論 1 290
  • 那天逃顶,我揣著相機(jī)與錄音讨便,去河邊找鬼。 笑死以政,一個(gè)胖子當(dāng)著我的面吹牛霸褒,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播盈蛮,決...
    沈念sama閱讀 38,921評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼废菱,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起昙啄,我...
    開(kāi)封第一講書(shū)人閱讀 37,688評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤穆役,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后梳凛,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體耿币,經(jīng)...
    沈念sama閱讀 44,130評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評(píng)論 2 325
  • 正文 我和宋清朗相戀三年韧拒,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了淹接。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,617評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡叛溢,死狀恐怖塑悼,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情楷掉,我是刑警寧澤厢蒜,帶...
    沈念sama閱讀 34,276評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站烹植,受9級(jí)特大地震影響斑鸦,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜草雕,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評(píng)論 3 312
  • 文/蒙蒙 一巷屿、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧墩虹,春花似錦嘱巾、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,740評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至尖坤,卻和暖如春稳懒,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背慢味。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,967評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工场梆, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人纯路。 一個(gè)月前我還...
    沈念sama閱讀 46,315評(píng)論 2 360
  • 正文 我出身青樓或油,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親驰唬。 傳聞我的和親對(duì)象是個(gè)殘疾皇子顶岸,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容