線程同步

1. 同步代碼塊:java

爲了解決併發修改臨界區的問題,Java的多線程支持引入了同步監視器來解決這個問題。使用同步監視器的通用方法就是同步代碼塊。同步代碼塊的語法以下:編程

synchronized(obj){

    ...//此處的代碼就是同步代碼塊
}

synchronized後面括號中的obj就是同步監視器。上面代碼的含義:線程開始執行同步代碼塊以前,必須先得到對同步監視器的鎖定。安全

2. 同步方法:多線程

與同步代碼塊對應,Java的多線程安全支持還提供了同步方法,同步方法就是使用synchronized關鍵字來修飾某個方法,則該方法稱爲同步方法。對於同步方法而言,無需顯式指定同步監視器,同步方法的同步監視器是this,也就是該對象自己。併發

3. 釋放同步監視器的鎖定:工具

任何線程進入同步代碼塊、同步方法以前,必須先得到對同步監視器的鎖定,那麼什麼時候會釋放對同步監視器的鎖定呢?程序沒法顯式釋放對同步監視器的鎖定,線程會在以下幾種狀況下釋放對同步監視器的鎖定。this

  • 當前線程的同步方法、同步代碼塊執行結束,當前線程即釋放同步監視器。
  • 當前線程在同步方法、同步代碼塊中遇到break、return終止了該代碼塊、該方法的繼續執行,當前線程將會釋放同步監視器。
  • 當前線程在同步方法、同步代碼塊中出現了未處理的Error和Exception,致使了該方法、代碼塊異常結束時,當前線程會釋放對同步監視器的鎖定。
  • 當前線程執行同步代碼塊或同步方法時,程序執行了同步監視器對象的wait()方法,則當前線程暫停,並釋放同步監視器。

在以下所示的狀況下,線程不會釋放同步監視器:spa

  • 線程執行同步代碼塊或同步方法時,程序調用了Thread.sleep()或Thread.yield()方法來暫停當前線程的執行,當前線程不會釋放同步監視器。
  • 線程執行同步代碼塊時,其餘線程調用了該線程的suspend()方法將該線程掛起,該線程不會釋放同步監視器。固然,咱們應儘可能避免使用suspend()和resume()方法來控制線程。

4. 同步鎖:線程

從Java5開始,Java提供了一種功能更強大的線程同步機制---經過顯式定義同步鎖對象來實現同步。在這種機制下,同步鎖使用Lock對象充當。code

Lock提供了比同步方法和同步代碼塊更普遍的鎖定操做,Lock實現容許更靈活的結構,能夠具備差異很大的屬性,而且支持多個相關的Condition對象。

Lock是控制多個線程對共享資源進行訪問的工具。一般,鎖提供了對共享資源的獨佔訪問,每次只能有一個線程對Lock對象加鎖,線程開始訪問共享資源以前應先得到Lock對象。

某些鎖可能容許對共享資源的併發訪問,如ReadWriteLock。

Lock、ReadWriteLock是Java5 新提供的兩個根接口,併爲Lock提供了ReentrantLock實現類,爲ReadWriteLock提供了ReentrantReadWriteLock實現類。

在實現線程安全的控制中,比較經常使用的是ReentrantLock。使用ReentrantLock對象能夠顯式地加鎖、釋放鎖,一般建議使用finally塊來確保在必要時釋放鎖。

ReentrantLock(可重入鎖)具備可重入性,也就是說,一個線程能夠對已被加鎖的ReentrantLock鎖再次加鎖,ReentrantLock對象會維持一個計數器來追蹤lock()方法的嵌套調用,線程在每次調用lock()加鎖後,必須顯式調用unlock()來釋放鎖,因此一段被鎖保護的代碼能夠調用另外一個被相同鎖保護的方法。

雖然同步方法和同步代碼塊使得多線程安全編程很是方便,但有時須要以更靈活的方式使用鎖。Lock提供了同步方法和同步代碼塊所沒有的其餘功能,包括用於非塊結構的tryLock()方法,以及試圖獲取可中斷鎖的lockInterruptibly()方法,還有獲取超時失效鎖的tryLock(long time,TimeUnit unit)方法。

5. 死鎖:

相關文章
相關標籤/搜索