- 并發(fā)編程三要素
- 原子性: 關(guān)鍵包 atomic; 線程切換導(dǎo)致原子性問題
- 可見性: 關(guān)鍵字 volatile; 操作工作內(nèi)存副本機(jī)制導(dǎo)致可見性問題
- 有序性: 關(guān)鍵字 synchronized, Happens-Before規(guī)則; 并發(fā)操作通過鎖機(jī)制保證有序性
- 線程
- 創(chuàng)建
Thread.class; interface Runnable; interface Callable(Future, FutureTask); Executors thread pool - 狀態(tài)
new , runnable(調(diào)用start()后行拢,被調(diào)度前), running, block[wait(), lock(), sleep()/join()/IO], dead - 調(diào)度
分時(shí)調(diào)度竭缝,搶占調(diào)度(java 使用此調(diào)度算法,優(yōu)先讓優(yōu)先級(jí)高的線程執(zhí)行) - 守護(hù)線程
所有用戶線程都結(jié)束運(yùn)行暴浦,守護(hù)線程 會(huì)隨 JVM 一起結(jié)束工作;finally 語句塊可能無法被執(zhí)行砚哆。 - 上下文切換
cpu會(huì)為線程分配執(zhí)行的時(shí)間片纷铣,線程執(zhí)行到分配的時(shí)間片后,cpu會(huì)保存線程任務(wù)的狀態(tài)刁标,并加載另一個(gè)線程的任務(wù)狀態(tài)并執(zhí)行
每次切換可能消耗納秒量級(jí)時(shí)間
jvm 管理線程屬于系統(tǒng)管理顿锰,涉及了用戶態(tài)和內(nèi)核態(tài)的切換 - 阻塞等待
sleep 不釋放鎖
wait 釋放鎖
- 并發(fā)
- 指令重排:提高性能狐血,cpu和編譯器發(fā)起牡直,遵守as-if-serial與happens-before規(guī)則;坑: 多線程環(huán)境可能會(huì)導(dǎo)致非預(yù)期結(jié)果;解: volatile內(nèi)存屏障機(jī)制防止重排
- volatile:
可見性原理: 寫操作匯編指令添加 lock 前綴,將變更刷入主內(nèi)存并觸發(fā) MESI(多級(jí)緩存一致性協(xié)議)胜榔,無效掉其他核的該變量副本,促使其讀取時(shí)從主內(nèi)存重新加載
禁止指令重排原理:通過對(duì)volatile修飾的變量的讀寫操作前后添加內(nèi)存屏障以防止處理器重排序 - synchronized: 無狀態(tài)鎖->偏向鎖->輕量級(jí)鎖->重量級(jí)鎖
偏向鎖:Object Mark Word 線程ID指向自己泥兰,進(jìn)入同步塊時(shí)檢查此線程ID是否是自己膀捷,嘗試CAS修改失敗后升級(jí)輕量級(jí)鎖(自旋鎖)
輕量級(jí)鎖: Object Mark Word 指向Lock Record吃警,未獲得鎖時(shí)進(jìn)入50~100次自旋重復(fù)嘗試CAS修改Object Mark Word 以獲得鎖,最終升級(jí)為重量級(jí)鎖
重量級(jí)鎖:Object Mark Word 指向Monitor指針,monitorenter -> {同步代碼塊} ->monitorexit;監(jiān)視器鎖的實(shí)現(xiàn)依賴底層操作系統(tǒng)的Mutex lock(互斥鎖)實(shí)現(xiàn);wait/notify等方法也依賴于monitor對(duì)象,因此需要在synchronized中執(zhí)行wait/notify方法 - CAS:Compare and Swap
樂觀鎖+自旋
java.util.concurrent.atomic 的 Atomic* 類使用CAS來修改變量 - AQS :AbstractQueuedSynchronizer
用來構(gòu)建鎖和同步器的框架
ReentrantLock铐拐,Semaphore,ReentrantReadWriteLock,SynchronousQueue
核心思想:如果被請(qǐng)求的共享資源空閑纵穿,則將當(dāng)前請(qǐng)求資源的線程設(shè)置 為有效的工作線程达传,并且將共享資源設(shè)置為鎖定狀態(tài)搂妻。如果被請(qǐng)求的共享資源被占用,那么就將暫時(shí)獲取不到鎖的線程加入到CLH隊(duì)列(雙向鏈表)中阻塞等待喚醒并分配鎖扁瓢。
- 死鎖
多個(gè)線程同時(shí)持有其他線程需要獲取的資源,造成互相無限等待的狀態(tài)
四條件與對(duì)策
- 互斥條件: 無解
- 請(qǐng)求與保持條件:解:一次性申請(qǐng)所有資源
- 不剝奪條件: 解: 占有部分資源的線程若無法進(jìn)一步申請(qǐng)到其他資源則釋放自己的資源
- 循環(huán)等待條件: 解: 按序申請(qǐng)楣铁,反序釋放
ConcurrentHashMap
1.7 segment(對(duì)key的rehash的高位來定位seg) + table + HashEntry
通過鎖定segment來實(shí)現(xiàn)put線程安全
1.8 無segment溃列,rehash定位table后 , cas寫入first節(jié)點(diǎn)哭廉,或synchronized為first節(jié)點(diǎn)加鎖并插入節(jié)點(diǎn); 多線程協(xié)助擴(kuò)容機(jī)制
table容量為2的冪次:rehash & (size - 1) 來定位table相叁,位運(yùn)算高效
擴(kuò)容閾值0.75 : 一個(gè)均衡了時(shí)間和空間的點(diǎn)CopyOnWriteArrayList
讀寫分離: 寫入時(shí)完整拷貝舊數(shù)組辽幌,在副本上寫入
空間換時(shí)間
適用于讀多寫少
最終一致性ThreadLocal
每個(gè)線程持有一個(gè) ThreadLocalMap對(duì)象,key為ThreadLocal的弱引用椿访,value為強(qiáng)引用。
當(dāng)ThreadLocal被gc回收后成玫,value不會(huì)被回收,造成內(nèi)存泄漏哭当。
解:get后及時(shí)removeThreadPoolExecutor
核心參數(shù)
corePoolSize 核心線程數(shù)(每有一個(gè)任務(wù)創(chuàng)建一個(gè)線程,達(dá)到corePoolSize陋葡,并一直保持corePoolSize個(gè)活躍線程)
maximumPoolSize 最大線程數(shù)(超過workQueue.size的任務(wù)會(huì)在新創(chuàng)建的線程中執(zhí)行彻采,maximumPoolSize直至達(dá)到maximumPoolSize,結(jié)束后在keepAliveTime+unit后銷毀線程岭粤,直至剩下corePoolSize個(gè)線程)
workQueue (有界隊(duì)列 or 無界隊(duì)列)
其他參數(shù)
keepAliveTime特笋,unit
[threadFactory]
handler (達(dá)到maximumPoolSize后的拒絕策略)并發(fā)工具類
- Semaphore
信號(hào)量。指定并發(fā)數(shù)內(nèi)的線程可以獲得信號(hào)量雹有,并發(fā)訪問臨界資源,未獲得信號(hào)量的線程可選擇阻塞等待或者限時(shí)等待或者快速失敗 - CountDownLatch
倒計(jì)閘溜宽。在全部參與倒計(jì)的工作線程倒計(jì)至0后质帅,放行等待倒計(jì)的線程執(zhí)行。 - CyclicBarrier
循環(huán)柵欄嫉嘀。在全部參與的線程到達(dá)循環(huán)柵欄等待狀態(tài)后魄揉,放行全部參與線程執(zhí)行。