線程同步(互斥)
簡(jiǎn)介:同步(互斥)是相對(duì)于異步(并發(fā))的概念,線程同步設(shè)計(jì)到鎖的概念;
線程的兩大特性:1.可見性:當(dāng)一個(gè)對(duì)象在多個(gè)線程的工作內(nèi)存中都存在副本時(shí),一個(gè)內(nèi)存修改共享變量,其他線程也能看到被修改后的值;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?2.有序性:保證A線程和B線程有序執(zhí)行;
對(duì)象創(chuàng)建:主內(nèi)存(堆內(nèi)存) --------- ?每個(gè)線程-工作內(nèi)存(線程棧)【存儲(chǔ)主內(nèi)存對(duì)象的副本】;
同步機(jī)制:JDK5.0之前有synchronized修飾符和volatile修飾符,高級(jí)方式有鎖對(duì)象Lock;
synchronized同步鎖
作用:如果一個(gè)代碼塊被synchronized修飾,當(dāng)一個(gè)線程獲取了對(duì)應(yīng)的鎖并執(zhí)行該代碼塊時(shí),其他線程便只能一直等待直到獲取鎖的線程釋放鎖;
釋放鎖的情況:1.獲取鎖的線程執(zhí)行完了該代碼塊,然后線程釋放對(duì)鎖的占有;
? ? ? ? ? ? ? ? ? ? ? ? ?2.線程執(zhí)行發(fā)生異常,此時(shí)JVM會(huì)讓線程自動(dòng)釋放鎖;
缺陷:1.獲取鎖的線程由于要等待IO或者其他原因(比如調(diào)用sleep方法)被阻塞了且未釋放鎖,其他線程便只能等待;(影響程序執(zhí)行效率)
? ? ? ? ? ?2.多個(gè)線程進(jìn)行讀操作,一個(gè)線程進(jìn)行讀操作,其他只能等待;(無法并發(fā)進(jìn)行讀操作)
?每個(gè)鎖對(duì)象都有兩個(gè)隊(duì)列:
1.就緒隊(duì)列:存儲(chǔ)了將要獲得鎖的線程(當(dāng)一個(gè)線程被喚醒(notify)后,才會(huì)進(jìn)入到就緒隊(duì)列,等待CPU的調(diào)度)
2.阻塞隊(duì)列:存儲(chǔ)了被阻塞的線程(當(dāng)一個(gè)線程被wait后,就會(huì)進(jìn)入阻塞隊(duì)列,等待下一次被喚醒)
過程:獲得同步鎖——清空工作內(nèi)存——拷貝對(duì)象副本,執(zhí)行對(duì)象方法——刷新主內(nèi)存——釋放同步鎖

volatile
用來修飾變量,內(nèi)存模型(主內(nèi)存和線程工作內(nèi)存)確保所有線程可以看到一致的變量值。
volatile是一種弱的同步手段,相對(duì)于synchronized來說,某些情況下使用,可能效率更高,因?yàn)樗皇亲枞?,尤其是讀操作時(shí),加與不加貌似沒有影響,處理寫操作的時(shí)候,可能消耗的性能更多些。
Lock
Lock接口 實(shí)現(xiàn)提供了比使用synchronized?方法和語句可獲得的更廣泛的鎖定操作,它能以更優(yōu)雅的方式處理線程同步問題。
Lock接口中方法:lock():獲取鎖,如果鎖已被其他線程獲取,則進(jìn)行等待;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?tryLock():用來嘗試獲取鎖,會(huì)立即返回true/false(即鎖已被其他線程獲?。谀貌坏芥i時(shí)不會(huì)一直在那等待;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?tryLock(long time, TimeUnit unit):拿不到鎖時(shí)會(huì)等待一定的時(shí)間,在時(shí)間期限之內(nèi)如果還拿不到鎖就返回false;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?lockInterruptibly():通過這個(gè)方法去獲取鎖時(shí),如果線程正在等待獲取鎖,則這個(gè)線程能夠響應(yīng)中斷,即中斷線程的等待狀態(tài);
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(個(gè)人理解:只要有人搶到了這份活,其他人就可以退出,不再等待的場(chǎng)景)
ReentrantLock:唯一實(shí)現(xiàn)了Lock接口的類;
? ??????????????????????????new?ReentrantLock(true):設(shè)置鎖的公平性;
? ? ? ? ? ? ? ? ? ? ? ? ? ? isFair():判斷鎖是否是公平鎖;
? ? ? ? ? ? ? ? ? ? ? ?isLocked():判斷鎖是否被任何線程獲取了;
????????????????????????isHeldByCurrentThread():判斷鎖是否被當(dāng)前線程獲取了;
????????????????????????????hasQueuedThreads():判斷是否有線程在等待該鎖;
ReadWriteLock接口:定義了readLock()和writeLock()方法,將文件的讀寫操作分開,分成2個(gè)鎖來分配給線程,使多個(gè)線程可同時(shí)進(jìn)行讀操作;
ReentrantReadWriteLock:實(shí)現(xiàn)了ReadWriteLock接口的類;


synchronized與Lock
synchronized:1.java語言關(guān)鍵字,內(nèi)置特性;
? ? ? ? ? ? ? ? ? ? ? ? ?2.系統(tǒng)自帶讓線程釋放對(duì)鎖的占用;
Lock:1.Java 5后在java.util.concurrent.locks包下實(shí)現(xiàn)同步訪問的接口;
? ? ? ? ? ?2.需手動(dòng)釋放鎖,否則可能死鎖;
Lock優(yōu)勢(shì):1.可以不讓等待的線程一直無期限地等待下去(比如只等待一定的時(shí)間或者能夠響應(yīng)中斷);
? ? ? ? ? ? ? ? ? ?2.通過Lock可以知道線程有沒有成功獲取到鎖;
? ? ? ? ? ? ? ? ? ?3.讓多個(gè)線程并發(fā)讀?。唬ㄌ岣叨鄠€(gè)線程進(jìn)行讀操作的效率)
總結(jié):在性能上來說,如果競(jìng)爭(zhēng)資源不激烈,兩者的性能是差不多的
? ? ? ? ? ?而當(dāng)競(jìng)爭(zhēng)資源非常激烈時(shí)(即有大量線程同時(shí)競(jìng)爭(zhēng)),此時(shí)Lock的性能要遠(yuǎn)遠(yuǎn)優(yōu)于synchronized
鎖的分類
可重入鎖:具備可重入性的鎖,synchronized和ReentrantLock都是可重入鎖;
? ? ? ? ? ? ? ? ? 1.可重入性即已經(jīng)獲取了鎖的線程再次遇到鎖方法不必重新申請(qǐng)鎖;
? ? ? ? ? ? ? ? ? 2.表明鎖的分配機(jī)制:基于線程的分配,而不是基于方法調(diào)用的分配;

可中斷鎖:可以相應(yīng)中斷的鎖,synchronized就不是可中斷鎖,而Lock是可中斷鎖;
????????????????(線程A執(zhí)行鎖中代碼,線程B等待,由于等的時(shí)間長不想等先處理其他事,就可以讓它中斷自己或在別的線程中中斷它)
公平鎖:盡量以請(qǐng)求鎖的順序來獲取鎖,synchronized就是非公平鎖,ReentrantLock和ReentrantReadWriteLock可設(shè)置(默認(rèn)非公平鎖);
? ? ? ? ? ? ? 1.有多個(gè)線程在等待一個(gè)鎖,當(dāng)這個(gè)鎖被釋放時(shí),等待時(shí)間最久的線程(最先請(qǐng)求的線程)會(huì)獲得該鎖;
? ? ? ? ? ? ? 2.非公平鎖即無法保證鎖的獲取是按照請(qǐng)求鎖的順序進(jìn)行的,可能導(dǎo)致某個(gè)或者一些線程永遠(yuǎn)獲取不到鎖;
讀寫鎖:將對(duì)一個(gè)資源(比如文件)的訪問分成了2個(gè)鎖,一個(gè)讀鎖和一個(gè)寫鎖;
? ? ? ? ? ? ? ?1.使得多個(gè)線程之間的讀操作不會(huì)發(fā)生沖突;
? ? ? ? ? ? ? ?2.ReadWriteLock就是讀寫鎖,它是一個(gè)接口,ReentrantReadWriteLock實(shí)現(xiàn)了這個(gè)接口;