Java多线程知识小抄集(四)——完结
歡迎支持筆者新作:《深入理解Kafka:核心設(shè)計(jì)與實(shí)踐原理》和《RabbitMQ實(shí)戰(zhàn)指南》,同時(shí)歡迎關(guān)注筆者的微信公眾號(hào):朱小廝的博客。
歡迎跳轉(zhuǎn)到本文的原文鏈接:https://honeypps.com/java/java-multiple-thread-summary-4/
本文主要整理博主遇到的Java多線程的相關(guān)知識(shí)點(diǎn),適合速記,故命名為“小抄集”。本文沒(méi)有特別重點(diǎn),每一項(xiàng)針對(duì)一個(gè)多線程知識(shí)做一個(gè)概要性總結(jié),也有一些會(huì)帶一點(diǎn)例子,習(xí)題方便理解和記憶。
更多內(nèi)容可以查閱:
Java多線程知識(shí)小抄集(一)
Java多線程知識(shí)小抄集(二)
Java多線程知識(shí)小抄集(三)
68. 如何避免死鎖
死鎖是指兩個(gè)或兩個(gè)以上的進(jìn)程在執(zhí)行過(guò)程中,因爭(zhēng)奪資源而造成的一種互相等待的現(xiàn)象,若無(wú)外力作用,他們都將無(wú)法推進(jìn)下去。這是一個(gè)嚴(yán)重的問(wèn)題,因?yàn)樗梨i會(huì)讓你的程序掛起無(wú)法完成任務(wù),死鎖的發(fā)生必須滿足一下4個(gè)條件:
互斥條件:一個(gè)資源每次只能被一個(gè)進(jìn)程使用。
請(qǐng)求與保持條件:一個(gè)進(jìn)程因請(qǐng)求資源而阻塞時(shí),對(duì)已獲得的資源保持不放。
不剝奪條件:進(jìn)程已獲得的資源,在未使用完之前,不能強(qiáng)行剝奪。
循環(huán)等待條件:若干進(jìn)程之間形成一種頭尾相接的循環(huán)等待資源關(guān)系。
避免死鎖最簡(jiǎn)單的方法就是阻止循環(huán)等待條件,將系統(tǒng)中所有的資源設(shè)置標(biāo)志位、排序,規(guī)定所有的進(jìn)程申請(qǐng)資源必須以一定的順序做操作來(lái)避免死鎖。
69. 怎么檢測(cè)一個(gè)線程是否擁有鎖
java.lang.Thread中有一個(gè)方法:public static native boolean holdsLock(Object obj). 當(dāng)且僅當(dāng)當(dāng)前線程擁有某個(gè)具體對(duì)象的鎖時(shí)返回true
70. 如何查看線程快照?
jstack命令用來(lái)生成虛擬機(jī)當(dāng)前的線程快照信息,線程快照就是當(dāng)前虛擬機(jī)每一個(gè)線程正在執(zhí)行的方法堆棧的集合。生成線程快照的目的主要是為了定位線程長(zhǎng)時(shí)間沒(méi)有響應(yīng)的原因,如線程死鎖、網(wǎng)絡(luò)請(qǐng)求沒(méi)有設(shè)置超時(shí)時(shí)間而長(zhǎng)時(shí)間沒(méi)有返回、死循環(huán)、信號(hào)量沒(méi)有釋放等,都有可能導(dǎo)致線程長(zhǎng)時(shí)間停頓。這是如果能夠dump出當(dāng)前JVM的線程快照,就能夠看出沒(méi)有響應(yīng)的線程究竟在做什么事情,從而定位問(wèn)題。
語(yǔ)法:
稍加翻譯一下:
-F 用來(lái)在輸出不被響應(yīng)時(shí)強(qiáng)制生成線程的快照
-m用來(lái)答應(yīng)出包含Java和native代碼的所有堆棧信息
-l 打印出鎖的附加信息
可以配合jps命令找出pid
71. JAVA中的線程調(diào)度算法
搶占式。一個(gè)線程用完CPU之后,操作系統(tǒng)會(huì)根據(jù)現(xiàn)場(chǎng)優(yōu)先級(jí)、線程饑餓情況等數(shù)據(jù)算出一個(gè)總的優(yōu)先級(jí)并分配下一個(gè)時(shí)間片給某個(gè)線程執(zhí)行。
72. Thread.sleep(0)有什么作用?
由于Java采用搶占式的線程調(diào)度算法,因此可能會(huì)出現(xiàn)某條線程嘗嘗獲取到CPU控制權(quán)的情況,為了讓某些優(yōu)先級(jí)比較低的線程能獲取到CPU控制權(quán),可以使用Thread.sleep(0)手動(dòng)觸發(fā)一次操作系統(tǒng)分配時(shí)間片的操作,這也是平衡CPU控制權(quán)的一種操作。
73. CAS
全稱(chēng)CompareAndSwap。假設(shè)有三個(gè)操作數(shù):內(nèi)存值V,舊的預(yù)期值A(chǔ),要修改的值B,當(dāng)且僅當(dāng)預(yù)期值A(chǔ)和內(nèi)存值V相同時(shí),才會(huì)將內(nèi)存值修改為B并返回true,否則什么都不做并返回false。當(dāng)然CAS一定要配合volatile變量,這樣才能保證每次拿到的遍歷是主內(nèi)存中最新的那個(gè)值,否則舊的預(yù)期值A(chǔ)對(duì)某條線程來(lái)說(shuō),永遠(yuǎn)是一個(gè)不會(huì)變的值A(chǔ),只要某次CAS操作失敗,永遠(yuǎn)都不可能成功。
74. AQS
全稱(chēng)AbstractQueuedSynchronizer。如果說(shuō)JUC(java.util.concurrent)的基礎(chǔ)是CAS的話,那么AQS就是整個(gè)JAVA并發(fā)包的核心了,ReentrantLock, ReentrantReadWriteLock, CountDownLatch, Semaphore等都用到了它。
75.合理地配置線程池
需要針對(duì)具體情況而具體處理,不同的任務(wù)類(lèi)別應(yīng)采用不同規(guī)模的線程池,任務(wù)類(lèi)別可劃分為CPU密集型任務(wù)、IO密集型任務(wù)和混合型任務(wù)。
- 對(duì)于CPU密集型任務(wù):線程池中線程個(gè)數(shù)應(yīng)盡量少,不應(yīng)大于CPU核心數(shù);
- 對(duì)于IO密集型任務(wù):由于IO操作速度遠(yuǎn)低于CPU速度,那么在運(yùn)行這類(lèi)任務(wù)時(shí),CPU絕大多數(shù)時(shí)間處于空閑狀態(tài),那么線程池可以配置盡量多些的線程,以提高CPU利用率;
- 對(duì)于混合型任務(wù):可以拆分為CPU密集型任務(wù)和IO密集型任務(wù),當(dāng)這兩類(lèi)任務(wù)執(zhí)行時(shí)間相差無(wú)幾時(shí),通過(guò)拆分再執(zhí)行的吞吐率高于串行執(zhí)行的吞吐率,但若這兩類(lèi)任務(wù)執(zhí)行時(shí)間有數(shù)據(jù)級(jí)的差距,那么沒(méi)有拆分的意義。
76. 多線程三大定律
–Gene Amdahl 發(fā)現(xiàn)在計(jì)算機(jī)體系架構(gòu)設(shè)計(jì)過(guò)程中,某個(gè)部件的優(yōu)化對(duì)整個(gè)架構(gòu)的優(yōu)化和改善是有上限的。這個(gè)發(fā)現(xiàn)后來(lái)成為知名的Amdahl 定律。
比如:即使你有10個(gè)老婆,也不能一個(gè)月把孩子生下來(lái)。
–Gustafson假設(shè)隨著處理器個(gè)數(shù)的增加,并行與串行的計(jì)算總量也是可以增加的。Gustafson定律認(rèn)為加速系數(shù)幾乎跟處理器個(gè)數(shù)成正比,如果現(xiàn)實(shí)情況符合Gustafson定律的假設(shè)前提的話,那么軟件的性能將可以隨著處理個(gè)數(shù)的增加而增加。
比如:當(dāng)你有10個(gè)老婆,就會(huì)要生更多的孩子。
–充分利用存儲(chǔ)空間等計(jì)算資源,盡量增大問(wèn)題規(guī)模以產(chǎn)生更好/更精確的解。
比如:你要設(shè)法讓每個(gè)老婆都在干活,別讓她們閑著。
77. 進(jìn)程間通信方式
- 管道( pipe ):管道是一種半雙工的通信方式,數(shù)據(jù)只能單向流動(dòng),而且只能在具有親緣關(guān)系的進(jìn)程間使用。進(jìn)程的親緣關(guān)系通常是指父子進(jìn)程關(guān)系。
- 有名管道 (named pipe) : 有名管道也是半雙工的通信方式,但是它允許無(wú)親緣關(guān)系進(jìn)程間的通信。
- 信號(hào)量( semophore ) : 信號(hào)量是一個(gè)計(jì)數(shù)器,可以用來(lái)控制多個(gè)進(jìn)程對(duì)共享資源的訪問(wèn)。它常作為一種鎖機(jī)制,防止某進(jìn)程正在訪問(wèn)共享資源時(shí),其他進(jìn)程也訪問(wèn)該資源。因此,主要作為進(jìn)程間以及同一進(jìn)程內(nèi)不同線程之間的同步手段。
- 消息隊(duì)列( message queue ) : 消息隊(duì)列是由消息的鏈表,存放在內(nèi)核中并由消息隊(duì)列標(biāo)識(shí)符標(biāo)識(shí)。消息隊(duì)列克服了信號(hào)傳遞信息少、管道只能承載無(wú)格式字節(jié)流以及緩沖區(qū)大小受限等缺點(diǎn)。
- 信號(hào) ( sinal ) : 信號(hào)是一種比較復(fù)雜的通信方式,用于通知接收進(jìn)程某個(gè)事件已經(jīng)發(fā)生。
- 共享內(nèi)存( shared memory ) :共享內(nèi)存就是映射一段能被其他進(jìn)程所訪問(wèn)的內(nèi)存,這段共享內(nèi)存由一個(gè)進(jìn)程創(chuàng)建,但多個(gè)進(jìn)程都可以訪問(wèn)。共享內(nèi)存是最快的 IPC 方式,它是針對(duì)其他進(jìn)程間通信方式運(yùn)行效率低而專(zhuān)門(mén)設(shè)計(jì)的。它往往與其他通信機(jī)制,如信號(hào)兩,配合使用,來(lái)實(shí)現(xiàn)進(jìn)程間的同步和通信。
- 套接字( socket ) : 套解口也是一種進(jìn)程間通信機(jī)制,與其他通信機(jī)制不同的是,它可用于不同及其間的進(jìn)程通信。
持續(xù)更新中~
博主嘔心瀝血整理發(fā)布,跪求一贊。
參考資料
歡迎跳轉(zhuǎn)到本文的原文鏈接:https://honeypps.com/java/java-multiple-thread-summary-4/
歡迎支持筆者新作:《深入理解Kafka:核心設(shè)計(jì)與實(shí)踐原理》和《RabbitMQ實(shí)戰(zhàn)指南》,同時(shí)歡迎關(guān)注筆者的微信公眾號(hào):朱小廝的博客。
總結(jié)
以上是生活随笔為你收集整理的Java多线程知识小抄集(四)——完结的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Java虚拟机结构分析
- 下一篇: 聊一聊ThreadLocal