深入理解java虚拟机--线程安全与锁优化
深入理解java虛擬機(jī)--線程安全與鎖優(yōu)化
- 面向過程編程思想和面向?qū)ο缶幊趟枷?/li>
- java語言中的線程安全
- 線程安全的實(shí)現(xiàn)方法
- 鎖優(yōu)化
面向過程編程思想和面向?qū)ο缶幊趟枷?/h2>
面向過程編程思想:站在計(jì)算機(jī)的角度,以算法為核心,數(shù)據(jù)是客體,程序代碼處理數(shù)據(jù)。
面向?qū)ο缶幊趟枷?#xff1a;站在現(xiàn)實(shí)世界的角度,數(shù)據(jù)和行為視為對(duì)象的一部分。
java語言中的線程安全
5類共享數(shù)據(jù)類別:1.不可變;2.絕對(duì)線程安全;3.相對(duì)線程安全;4.線程兼容;5.線程對(duì)立。
不可變帶來的安全性是最簡(jiǎn)單和最純粹的。基本數(shù)據(jù)類型,final關(guān)鍵字修飾;共享數(shù)據(jù)是一個(gè)對(duì)象,對(duì)象的行為用final修飾。
定義:當(dāng)多個(gè)線程訪問一個(gè)對(duì)象時(shí),如果不用考慮這些線程在運(yùn)行時(shí)環(huán)境下的調(diào)度和交替執(zhí)行,也不需要進(jìn)行額外的同步,或者在調(diào)用方進(jìn)行任何其他的協(xié)調(diào)操作,調(diào)用這個(gè)對(duì)象的行為都可以獲得正確的結(jié)果,那這個(gè)對(duì)象是線程安全的。
單獨(dú)操作是線程安全的;需要額外的同步手段(特定順序的連續(xù)調(diào)用)。
例子:Vector的get()、remove()、size()等方法;其他類如:HashTable等。
本身不是線程安全的;需要正確使用同步手段。
例子:Vector的get()、remove()、size()等方法;其他類如:ArrayList、HashMap等。
無論是采取何種同步措施,都無法達(dá)到線程安全的。
例子:Thread類的suspend()和resume();其他類如:System類的setInt()、setOut()和runFinalizersOnExit()等。
線程安全的實(shí)現(xiàn)方法
3種實(shí)現(xiàn)方法:1.互斥同步;2.非阻塞同步;3.無同步方案。
也稱阻塞同步;互斥是方法,同步是目的;互斥的實(shí)現(xiàn)方式主要有三種:臨界區(qū),互斥量,信號(hào)量。實(shí)現(xiàn)同步手段:synchronized和ReentrantLock。
-
synchronized:原生語法層面的互斥;關(guān)鍵字經(jīng)過編譯后在同步塊前后形成monitorenter和monitorexit兩個(gè)字節(jié)碼指令,這兩字字節(jié)碼指令都需要一個(gè)reference類型的參數(shù)來指明要鎖定和解鎖的對(duì)象;如果synchronized修飾的實(shí)例方法則去取對(duì)應(yīng)的對(duì)象實(shí)例,如果修飾的是類方法,則去取Class對(duì)象所為鎖對(duì)象。有兩點(diǎn)要注意的:1.synchronized同步塊對(duì)同一條線程來說是可重入的,不會(huì)出現(xiàn)自己把自己鎖死的情況;2.同步塊在已進(jìn)入的線程執(zhí)行完之前,會(huì)阻塞后面其他線程的進(jìn)入。
-
ReentrantLock:API層面的互斥;相對(duì)于synchronized來說有三個(gè)高級(jí)特性:1.等待可中斷;2.可實(shí)現(xiàn)公平鎖;3.鎖可以綁定多個(gè)條件;
-
synchronized和ReentrantLock吞吐量比較
jdk1.5版本:ReentrantLock>synchronized;
jdk1.6后版本:synchronized、ReentrantLock兩者持平; -
處理問題方式角度:互斥同步是悲觀策略。
阻塞和喚醒一個(gè)線程,需要從用戶態(tài)轉(zhuǎn)換到核心態(tài),消耗性能。
-
定義
基于沖突檢測(cè)的樂觀并發(fā)策略,先進(jìn)行操作,如果沒有其他線程的競(jìng)爭(zhēng)共享數(shù)據(jù),那操作就是成功了;如果共享數(shù)據(jù)有爭(zhēng)用,產(chǎn)生了沖突,那就再采取其他的補(bǔ)充措施(最常見的補(bǔ)償措施就是不斷的重試,直到成功為止),這種樂觀的策略很多實(shí)現(xiàn)都不需要把線程掛起。
-
處理問題方式角度:非阻塞同步是樂觀策略。
-
CAS指令
內(nèi)存位置(V)、舊的預(yù)期值(A)、新值(B);
CAS指令執(zhí)行時(shí),當(dāng)且僅當(dāng)V符合舊預(yù)期值A(chǔ)時(shí),處理器用新值B更新V的值,否則它就不執(zhí)行更新,但是無論是否更新了V的值,都會(huì)返回V的舊值,上述的處理過程是一個(gè)原子操作。CAS漏銅,ABA問題:
如果一個(gè)變量V初次讀取的時(shí)候是A值,并且在準(zhǔn)備賦值的時(shí)候檢查到它仍然是A值,那我們就能說它的值沒有被其他線程改變過了嗎?如果在這段期間它的值曾經(jīng)被改成了B,后來又被改成了A,那CAS操作就會(huì)誤認(rèn)為它從來沒有被改變過。
無同步方案
2類:1.可重入代碼;2.線程本地存儲(chǔ)。
可重入代碼
3個(gè)特征:不依賴存儲(chǔ)在堆上的數(shù)據(jù)和公用的系統(tǒng)資源、用到的狀態(tài)量都是由參數(shù)傳入、不調(diào)用非可重入的方法。
線程本地存儲(chǔ)
例子:生產(chǎn)者-消費(fèi)者:Web交互模型中的"一個(gè)請(qǐng)求對(duì)應(yīng)一個(gè)服務(wù)器線程"的處理方式。
鎖優(yōu)化
5種鎖優(yōu)化:1.自旋鎖和自適應(yīng)自旋;2.鎖消除;3.鎖粗化;4.輕量級(jí)鎖;5.偏向鎖。
- 自旋鎖定義
是指嘗試獲取鎖的線程不會(huì)立即阻塞,而是采用循環(huán)的方式去嘗試獲取鎖。 - 自適應(yīng)自旋定義
- 自旋的時(shí)間不在固定,由前一次在同一個(gè)鎖上的自旋時(shí)間及鎖的擁有者的狀態(tài)決定。
- 原因
- 掛起線程和喚醒線程會(huì)消耗處理器時(shí)間
- 共享數(shù)據(jù)的鎖定狀態(tài)很多情況只會(huì)持續(xù)很短的時(shí)間
- 定義
指在虛擬機(jī)即時(shí)編譯器在運(yùn)行時(shí),對(duì)一些代碼上要求同步,但是被檢測(cè)到不可能存在共享數(shù)據(jù)競(jìng)爭(zhēng)的鎖進(jìn)行消除。
鎖粗化
范圍擴(kuò)大,如果虛擬機(jī)探測(cè)到有這樣的一串零碎的操作都是對(duì)同一個(gè)對(duì)象加鎖,將會(huì)把加鎖同步的范圍擴(kuò)展(粗化)到整個(gè)操作序列的外部,這樣只需要加鎖一次就可以了。
輕量級(jí)鎖
- 沒有多線程的競(jìng)爭(zhēng)前提下;減少傳統(tǒng)的重量級(jí)所使用操作系統(tǒng)互斥量產(chǎn)生的性能消耗。
- Mark Word
- 消除數(shù)據(jù)在無競(jìng)爭(zhēng)情況下的同步原語,進(jìn)一步提高程序的運(yùn)行性能。
- 不用做CAS操作。
總結(jié)
以上是生活随笔為你收集整理的深入理解java虚拟机--线程安全与锁优化的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 学习进度条07
- 下一篇: webstorm破解方法