《併發編程》--18.Java層鎖的優化

1 減少鎖持有時間

public synchronized void syncMethod(){ 
 	othercode1(); 
 	mutextMethod(); 
 	othercode2(); 
 }
像上述代碼這樣,在進入方法前就要得到鎖,其他線程就要在外面等待。
這裏優化的一點在於,要減少其他線程等待的時間,所以,只用在有線程安全要求的程序上加鎖

public void syncMethod(){ 
 	othercode1(); 
 	synchronized(this){
 		mutextMethod(); 
 	}
 	othercode2(); 
 }
2 減小鎖粒度
將大對象(這個對象可能會被很多線程訪問),拆成小對象,大大增加並行度,降低鎖競爭。降低了鎖的競爭,偏向鎖,輕量級鎖成功率纔會提高。
最最典型的減小鎖粒度的案例就是ConcurrentHashMap。
3 鎖分離
最常見的鎖分離就是讀寫鎖ReadWriteLock,根據功能進行分離成讀鎖和寫鎖,這樣讀讀不互斥,讀寫互斥,寫寫互斥,即保證了線程安全,又提高了性能。
讀寫分離思想可以延伸,只要操作互不影響,鎖就可以分離。
比如LinkedBlockingQueue 詳情查看    《併發編程》--17.BlockingQueue解析

4 鎖粗化
通常情況下,爲了保證多線程間的有效併發,會要求每個線程持有鎖的時間儘量短,即在使用完公共資源後,應該立即釋放鎖。只有這樣,等待在這個鎖上的其他線程才能儘早的獲得資源執行任務。但是,凡事都有一個度,如果對同一個鎖不停的進行請求、同步和釋放,其本身也會消耗系統寶貴的資源,反而不利於性能的優化 。
舉個例子:

public void demoMethod(){ 
 synchronized(lock){ 
 	//do sth. 
     } 
       //做其他不需要的同步的工作,但能很快執行完畢 
       synchronized(lock){ 
       //do sth. 
     } 
 }
這種情況,根據鎖粗化的思想,應該合併
public void demoMethod(){ 
 	//整合成一次鎖請求 
 	synchronized(lock){ 
 	//do sth. 
	 //做其他不需要的同步的工作,但能很快執行完畢 
     }
 }
public void demoMethod(){ 
 	//整合成一次鎖請求 
        synchronized(lock){ 
 	//do sth. 
 	//做其他不需要的同步的工作,但能很快執行完畢 
     }
 }
當然這是有前提的,前提就是中間的那些不需要同步的工作是很快執行完成的。
再舉一個極端的例子:
for(int i=0;i<CIRCLE;i++){ 
	 synchronized(lock){  
 	} 
 }
for(int i=0;i<CIRCLE;i++){ 
 	synchronized(lock){  
        } 
 }
 //在一個循環內不同得獲得鎖。雖然JDK內部會對這個代碼做些優化,但是還不如直接寫成
synchronized(lock){ 
 for(int i=0;i<CIRCLE;i++){ 
  
	 } 
 }
synchronized(lock){ 
 for(int i=0;i<CIRCLE;i++){ 
  
 } 
 }

當然如果有需求說,這樣的循環太久,需要給其他線程不要等待太久,那隻能寫成上面那種。如果沒有這樣類似的需求,還是直接寫成下面


那種比較好。

發佈了152 篇原創文章 · 獲贊 24 · 訪問量 20萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章