基本概念
1. 同步和異步
- 同步和異步通常用來(lái)形容一次方法調(diào)用
- 同步方法調(diào)用一旦開(kāi)始,調(diào)用者必須等到方法調(diào)用返回后奴拦,才能繼續(xù)后續(xù)的行為媒鼓。
- 異步方法調(diào)用更像一個(gè)消息傳遞,一旦開(kāi)始错妖,方法調(diào)用就會(huì)以及返回绿鸣,調(diào)用者就可以繼續(xù)后續(xù)的工作。如果異步調(diào)用需要返回結(jié)果暂氯,那么當(dāng)這個(gè)異步調(diào)用真實(shí)完成時(shí)則會(huì)通知調(diào)用者潮模。
2. 并行和并發(fā)
- 都表示兩個(gè)或多個(gè)任務(wù)一起執(zhí)行。
- 并發(fā)偏重多個(gè)任務(wù)交替執(zhí)行痴施,而多個(gè)任務(wù)之間有可能還是串行的擎厢。
- 并行是真正意義上的“同時(shí)執(zhí)行”。
3. 臨界區(qū)
- 用來(lái)表示一種公共資源或者說(shuō)是共享數(shù)據(jù)辣吃,可以被多個(gè)線程使用锉矢。但是每一次只有一個(gè)線程可以使用它,其他線程必須等待齿尽。
4. 阻塞和非阻塞
- 阻塞:一個(gè)線程占用了臨界區(qū)資源沽损,那么其他所有需要這個(gè)資源的線程就必須在這個(gè)臨界區(qū)中進(jìn)行等待,導(dǎo)致線程掛起循头。
- 非阻塞:與之相反绵估,強(qiáng)調(diào)沒(méi)有一個(gè)線程可以妨礙其他線程執(zhí)行炎疆,所有線程都會(huì)嘗試不斷向前執(zhí)行。
5. 死鎖国裳、饑餓形入、活鎖
- 都是線程活躍性問(wèn)題。
- 死鎖:四輛小車問(wèn)題缝左。各自占用了其他線程請(qǐng)求的資源亿遂,同時(shí)又在請(qǐng)求其他線程所占有的資源,而且都不肯釋放渺杉,導(dǎo)致死鎖蛇数。
- 饑餓:一個(gè)線程因?yàn)槟撤N原因(優(yōu)先級(jí)低)一直無(wú)法獲得所需要的資源,導(dǎo)致無(wú)法運(yùn)行是越。相較于死鎖耳舅,活鎖在未來(lái)一段時(shí)間內(nèi)可以解決
- 活鎖:線程互相謙讓,主動(dòng)將資源釋放給他人使用倚评,導(dǎo)致資源在兩個(gè)線程之間不斷跳動(dòng)浦徊,沒(méi)有一個(gè)線程可以同時(shí)拿到所有資源而正常運(yùn)行,這就是活鎖天梧。
6. 并發(fā)級(jí)別
6.1 阻塞(blocking)
- 一個(gè)線程是阻塞的盔性,那么在其他線程釋放資源前,當(dāng)前線程無(wú)法執(zhí)行呢岗。使用sychronized和重入鎖時(shí)纯出,得到阻塞線程。
6.2 無(wú)饑餓(starving-free)
- 由于線程優(yōu)先級(jí)敷燎,線程調(diào)度時(shí)總會(huì)傾向于滿足高優(yōu)先級(jí)的進(jìn)程暂筝,所以是非公平的,就會(huì)產(chǎn)生饑餓硬贯。
- 采用公平的鎖焕襟,線程都可以執(zhí)行,就是無(wú)饑餓的饭豹。
6.3 無(wú)障礙(obstruction-free)
- 最弱的非阻塞調(diào)度鸵赖,兩個(gè)線程都是無(wú)障礙的執(zhí)行,那么不會(huì)因?yàn)榕R界區(qū)的問(wèn)題導(dǎo)致一方被掛起拄衰。
- 如果都進(jìn)入了臨界區(qū)它褪,修改了共享數(shù)據(jù),發(fā)生沖突翘悉,就會(huì)回滾茫打。
- 相較于悲觀策略的阻塞方式,無(wú)障礙方式是樂(lè)觀的。
6.4 無(wú)鎖(lock-free)
- 無(wú)鎖的并行都是無(wú)障礙的老赤。無(wú)鎖下轮洋,所有線程都可以嘗試對(duì)臨界區(qū)進(jìn)行訪問(wèn),但是無(wú)鎖的并發(fā)保證必然有一個(gè)線程能夠在有限步內(nèi)完成操作離開(kāi)臨界區(qū)抬旺。
- 在臨界區(qū)競(jìng)爭(zhēng)失敗的線程弊予,會(huì)不斷重試知道成功,如果一直運(yùn)氣不好开财,就會(huì)饑餓汉柒,線程停止不前。
6.5 無(wú)等待(wait-free)
- 無(wú)鎖要求有一個(gè)線程可以在有限步內(nèi)完成操作责鳍。
- 無(wú)等待在無(wú)鎖的基礎(chǔ)上更進(jìn)一步碾褂,要求所有線程必須在有限步內(nèi)完成操作。這樣就沒(méi)有饑餓薇搁。
- 例如RCU(Read-copy-update):對(duì)數(shù)據(jù)讀不加控制斋扰,讀線程都是無(wú)等待的渡八,寫數(shù)據(jù)時(shí)啃洋,先取得原數(shù)據(jù)的副本,接著修改副本數(shù)據(jù)屎鳍,在合適的時(shí)機(jī)回寫數(shù)據(jù)宏娄。
7. JMM
7.1 原子性(Atomicity)
- 原子性指一個(gè)操作是不可中斷的。即使多個(gè)線程一起執(zhí)行的時(shí)候逮壁,一個(gè)操作一旦開(kāi)始孵坚,就不會(huì)被其他線程干擾。例如:int型變量賦值是原子的窥淆,long型不是(32位卖宠,64位區(qū)別)。
7.2 可見(jiàn)性(Visibility)
- 可見(jiàn)性指一個(gè)線程修改了一個(gè)共享變量的值忧饭,其他線程可以立刻知道此修改扛伍。
- 緩存優(yōu)化,硬件優(yōu)化词裤,指令重排序以及編輯器優(yōu)化都有可能導(dǎo)致這一問(wèn)題刺洒。
7.2 有序性(Ordering)
- 指令重排序后,寫在前面的代碼未必會(huì)先執(zhí)行吼砂。
- 在串行程序中逆航,指令重排不會(huì)影響語(yǔ)義邏輯。
- 并行程序中渔肩,線程A的指令執(zhí)行順序在線程B中是沒(méi)有保證的因俐。
- 指令重排可以提高CPU性能。
7.3 指令重排規(guī)則(Happen-before)
- 程序順序原則:一個(gè)線程內(nèi)保證語(yǔ)義的串行性
- volatile規(guī)則:volatile變量的寫,先發(fā)生于讀
- 鎖規(guī)則:unlock先于后面的lock
- 傳遞性:A先于B女揭,B先于C蚤假,則A先于C
- 線程的start()方法先于它的每一個(gè)動(dòng)作
- 線程的所有操作先于它的終結(jié)(Thread.join())
- 線程的中斷(interrupt())先于被中斷的代碼
- 對(duì)象的構(gòu)造函數(shù)執(zhí)行、結(jié)束先于finalize()方法