Lock接口與synchronized關(guān)鍵字的區(qū)別:
1.使用synchronized關(guān)鍵字將會(huì)隱式地獲取鎖,但是它將鎖的獲取和釋放固化了,也就是先獲取再釋放。當(dāng)然窃爷,這種方式簡化了同步的管理,可是擴(kuò)展性沒有顯示的鎖獲取和釋放來的好姓蜂。
2.Lock接口(以及相關(guān)實(shí)現(xiàn)類)提供了與synchronized關(guān)鍵字類似的同步功能按厘,只是在使用時(shí)需要顯式地獲取和釋放鎖。雖然它缺少了(通過synchronized塊或者方法所提供的)隱式獲取釋放鎖的便捷性钱慢,但是卻擁有了鎖獲取與釋放的可操作性逮京、可中斷的獲取鎖以 及超時(shí)獲取鎖等多種synchronized關(guān)鍵字所不具備的同步特性。
Lock使用示例:
Lock lock = new ReentrantLock();
lock.lock();
try{
do something....
}finally {
lock.unlock();
}
1.在finally塊中釋放鎖束莫,目的是保證在獲取到鎖之后懒棉,最終能夠被釋放。
2.不要將獲取鎖的過程寫在try塊中览绿,因?yàn)槿绻讷@取鎖(自定義鎖的實(shí)現(xiàn))時(shí)發(fā)生了異常策严,異常拋出的同時(shí),也會(huì)導(dǎo)致鎖無故釋放饿敲。
重入鎖:
1.重入鎖ReentrantLock妻导,顧名思義,就是支持重進(jìn)入的鎖怀各,它表示該鎖能夠支持一個(gè)線程對(duì)資源的重復(fù)加鎖倔韭。
2.而synchronized關(guān)鍵字隱式的支持重進(jìn)入,比如一個(gè)synchronized修飾的遞歸方 法瓢对,在方法執(zhí)行時(shí)寿酌,執(zhí)行線程在獲取了鎖之后仍能連續(xù)多次地獲得該鎖。
3.ReentrantLock雖然沒能像synchronized關(guān)鍵字一樣支持隱式的重進(jìn)入沥曹,但是在調(diào)用lock()方 法時(shí)份名,已經(jīng)獲取到鎖的線程,能夠再次調(diào)用lock()方法獲取鎖而不被阻塞妓美。
公平鎖與非公平鎖:
1.如果在絕對(duì)時(shí)間上僵腺,先對(duì)鎖進(jìn)行獲取的請(qǐng)求一定先被滿足,那么這個(gè)鎖是公平的壶栋,反之辰如,是不公平的。公平的獲取鎖贵试,也就是等待時(shí)間最長的線 程最優(yōu)先獲取鎖琉兜,也可以說鎖獲取是順序的。2.ReentrantLock提供了一個(gè)構(gòu)造函數(shù)毙玻,能夠控制鎖是否是公平的豌蟋。
3.公平的鎖機(jī)制往往沒有非公平的效率高,但是公平鎖能夠減少“饑餓”發(fā)生的概率桑滩,等待越久的請(qǐng)求越是能夠得到優(yōu)先滿足梧疲。
4.公平性鎖保證了鎖的獲取按照FIFO原則,而代價(jià)是進(jìn)行大量的線程切換运准。非公平性鎖雖然可能造成線程“饑餓”幌氮,但極少的線程切換,保證了其更大的吞吐量胁澳。
讀寫鎖
1.排他鎖:排他鎖在同一時(shí)刻只允許一個(gè)線程進(jìn)行訪問该互,大部分鎖(如Mutex和ReentrantLock)基本都是排他鎖。
2.讀寫鎖在同一時(shí)刻可以允許多個(gè)讀線程訪問韭畸,但是在寫線程訪問時(shí)宇智,所有的讀線程和其他寫線程均被阻塞。讀寫鎖維護(hù)了一對(duì)鎖胰丁,一個(gè)讀鎖和一個(gè)寫鎖普筹,通過分離讀鎖和寫鎖,使得并發(fā)性相比一般的排他鎖有了很大提升隘马。
3.一般情況下太防,讀寫鎖的性能都會(huì)比排它鎖好,因?yàn)榇蠖鄶?shù)場景讀是多于寫的酸员。在讀多于寫 的情況下蜒车,讀寫鎖能夠提供比排它鎖更好的并發(fā)性和吞吐量。Java并發(fā)包提供讀寫鎖的實(shí)現(xiàn)是 ReentrantReadWriteLock
Condition接口:
任意一個(gè)Java對(duì)象幔嗦,都擁有一組監(jiān)視器方法(定義在java.lang.Object上)酿愧,主要包括wait()、 wait(long timeout)邀泉、notify()以及notifyAll()方法嬉挡,這些方法與synchronized同步關(guān)鍵字配合钝鸽,可以 實(shí)現(xiàn)等待/通知模式。Condition接口也提供了類似Object的監(jiān)視器方法庞钢,與Lock配合可以實(shí)現(xiàn)等 待/通知模式拔恰,但是這兩者在使用方式以及功能特性上還是有差別的。
使用示例:
package cn.itcast.day06.demo6;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Solution {
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
public void conditionWait() throws InterruptedException {
lock.lock();
try{
condition.await();
}finally {
lock.unlock();
}
}
public void conditionSignal(){
lock.lock();
try {
condition.signal();
}finally {
lock.unlock();
}
}
}
一般都會(huì)將Condition對(duì)象作為成員變量基括。當(dāng)調(diào)用await()方法后颜懊,當(dāng)前線程會(huì) 釋放鎖并在此等待,而其他線程調(diào)用Condition對(duì)象的signal()方法风皿,通知當(dāng)前線程后河爹,當(dāng)前線程 才從await()方法返回,并且在返回前已經(jīng)獲取了鎖桐款。