減少鎖持有時間
對于使用鎖進(jìn)行并發(fā)控制的應(yīng)用程序來說,如果單個線程特有鎖的時間過長,會導(dǎo)致鎖的競爭更加激烈,會影響系統(tǒng)的性能.在程序中需要盡可能減少線程對鎖的持有時間,如下面代碼:
public synchronized void syncMethod(){
othercode1();
mutexMethod();
othercode();
}
在syncMethod同步方法中,假設(shè)只有mutexMethod()方法是需要同步的, othercode1()方法與othercode2()方法不需要進(jìn)行同步. 如果othercode1與othercode2這兩個方法需要花費(fèi)較長的CPU時間,在并發(fā)量較大的情況下,這種同步方案會導(dǎo)致等待線程的大量增加. 一個較好的優(yōu)化方案是,只在必要時進(jìn)行同步,可以減少鎖的持有時間,提高系統(tǒng)的吞吐量,如把上面的代碼改為:
public void syncMethod(){
othercode1();
synchronized (this) {
mutexMethod();
}
othercode();
}
只對mutexMethod()方法進(jìn)行同步,這種減少鎖持有時間有助于降低鎖沖突的可能性,提升系統(tǒng)的并發(fā)能力。
一個鎖保護(hù)的共享數(shù)據(jù)的數(shù)量大小稱為鎖的粒度. 如果一個鎖保護(hù)的共享數(shù)據(jù)的數(shù)量大就稱該鎖的粒度粗,否則稱該鎖的粒度細(xì).鎖的粒度過粗會導(dǎo)致線程在申請鎖時需要進(jìn)行不必要的等待.減少鎖粒度是一種削弱多線程鎖競爭的一種手段,可以提高系統(tǒng)的并發(fā)性。
在JDK7前,java.util.concurrent.ConcurrentHashMap類采用分段鎖協(xié)議,可以提高程序的并發(fā)性。
使用ReadWriteLock讀寫分離鎖可以提高系統(tǒng)性能, 使用讀寫分離鎖也是減小鎖粒度的一種特殊情況. 第二條建議是能分割數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)減小鎖的粒度,那么讀寫鎖是對系統(tǒng)功能點(diǎn)的分割。
在多數(shù)情況下都允許多個線程同時讀,在寫的使用采用獨(dú)占鎖,在讀多寫少的情況下,使用讀寫鎖可以大大提高系統(tǒng)的并發(fā)能力。
將讀寫鎖的思想進(jìn)一步延伸就是鎖分離.讀寫鎖是根據(jù)讀寫操作功能上的不同進(jìn)行了鎖分離.根據(jù)應(yīng)用程序功能的特點(diǎn),也可以對獨(dú)占鎖進(jìn)行分離.如java.util.concurrent.LinkedBlockingQueue類中take()與put()方法分別從隊(duì)頭取數(shù)據(jù),把數(shù)據(jù)添加到隊(duì)尾. 雖然這兩個方法都是對隊(duì)列進(jìn)行修改操作,由于操作的主體是鏈表,take()操作的是鏈表的頭部,put()操作的是鏈表的尾部,兩者并不沖突. 如果采用獨(dú)占鎖的話,這兩個操作不能同時并發(fā),在該類中就采用鎖分離,take()取數(shù)據(jù)時有取鎖, put()添加數(shù)據(jù)時有自己的添加鎖,這樣take()與put()相互獨(dú)立實(shí)現(xiàn)了并發(fā)。
為了保證多線程間的有效并發(fā),會要求每個線程持有鎖的時間盡量短.但是凡事都有一個度,如果對同一個鎖不斷的進(jìn)行請求,同步和釋放,也會消耗系統(tǒng)資源.如:
public void method1(){
synchronized( lock ){
同步代碼塊1
}
synchronized( lock ){
同步代碼塊2
}
}
JVM在遇到一連串不斷對同一個鎖進(jìn)行請求和釋放操作時,會把所有的鎖整合成對鎖的一次請求,從而減少對鎖的請求次數(shù),這個操作叫鎖的粗化,如上一段代碼會整合為:
public void method1(){
synchronized( lock ){
同步代碼塊1
同步代碼塊2
}
}
在開發(fā)過程中,也應(yīng)該有意識的在合理的場合進(jìn)行鎖的粗化,尤其在循環(huán)體內(nèi)請求鎖時,如:
for(int i = 0 ; i< 100; i++){
synchronized(lock){}
}
這種情況下,意味著每次循環(huán)都需要申請鎖和釋放鎖,所以一種更合理的做法就是在循環(huán)外請求一次鎖,如:
synchronized( lock ){
for(int i = 0 ; i< 100; i++){}
}