Java多線程七

1 synchronized的缺陷

參考:Java併發編程:Lock 
  synchronized是java中的一個關鍵字,也就是說是Java語言內置同步的特性。那麼爲什麼會出現Lock呢? 
  如果一個代碼塊被synchronized修飾了,當一個線程獲取了對應的鎖,並執行該代碼塊時,其他線程便只能一直等待,等待獲取鎖的線程釋放鎖,而這裏獲取鎖的線程釋放鎖只會有兩種情況: 
1. 獲取鎖的線程執行完了該代碼塊,然後線程釋放對鎖的佔有; 
2. 線程執行發生異常,此時JVM會讓線程自動釋放鎖。 
  那麼如果這個獲取鎖的線程由於要等待IO或者其他原因(比如調用sleep方法)被阻塞了,但是又沒有釋放鎖,其他線程便只能等待!效率隨之大大降低。

  因此就需要有一種機制可以不讓等待的線程一直無期限地等待下去(比如只等待一定的時間或者能夠響應中斷),通過Lock就可以辦到。

  再舉個例子:當有多個線程讀寫文件時,讀操作和寫操作會發生衝突現象,寫操作和寫操作會發生衝突現象,但是讀操作和讀操作不會發生衝突現象。 
  但是採用synchronized關鍵字來實現同步的話,就會導致一個問題: 
  如果多個線程都只是進行讀操作,所以當一個線程在進行讀操作時,其他線程只能等待無法進行讀操作。

  因此就需要一種機制來使得多個線程都只是進行讀操作時,線程之間不會發生衝突,通過ReadWriteLock就可以辦到。 
  另外,通過Lock可以知道線程有沒有成功獲取到鎖。這個是synchronized無法辦到的。 
  總結一下,也就是說Lock提供了比synchronized更多的功能。但是要注意以下幾點: 
1. Lock不是Java語言內置的,synchronized是Java語言的關鍵字,因此是內置特性。Lock是一個類,通過這個類可以實現同步訪問; 
2. Lock和synchronized有一點非常大的不同,採用synchronized不需要用戶去手動釋放鎖,當synchronized方法或者synchronized代碼塊執行完之後,系統會自動讓線程釋放對鎖的佔用;而Lock則必須要用戶去手動釋放鎖,如果沒有主動釋放鎖,就有可能導致出現死鎖現象。

2 java.util.concurrent.locks包簡介

  爲鎖定和等待條件提供一個框架的接口和類,它不同於內置同步和監視器。該框架允許更靈活地使用鎖定和條件,但以更難用的語法爲代價。 
  locks包下的類: 
      這裏寫圖片描述 
  java.util.concurrent.locks包的類結構圖:(查看大圖) 
java.util.concurrent.locks包的類結構圖
1. Lock 接口支持那些語義不同(重入、公平等)的鎖定規則,可以在非阻塞式結構的上下文(包括 hand-over-hand和鎖定重排算法)中使用這些規則。主要的實現是 ReentrantLock。 
2. ReadWriteLock 接口以類似方式定義了一些讀取者可以共享而寫入者獨佔的鎖定(讀與讀共享,寫與寫、讀與寫互斥)。此包只提供了一個實現,即 ReentrantReadWriteLock,因爲它適用於大部分的標準用法上下文。但程序員可以創建自己的、適用於非標準要求的實現。 
3. Condition 接口描述了可能會與鎖定有關聯的條件變量。這些變量在用法上與使用Object.wait、Object.notify訪問的隱式監視器類似,但提供了更強大的功能。需要特別指出的是,單個 Lock 可能與多個 Condition對象關聯。爲了避免兼容性問題,Condition 方法的名稱與對應的 Object 版本中的不同(例如使用await)。 
4. AbstractQueuedSynchronizer類是一個非常有用的超類,可用來定義鎖定以及依賴於排隊阻塞線程的其他同步器。 
5. LockSupport類提供了更低級別的阻塞和解除阻塞支持,這對那些實現自己的定製鎖定類的開發人員很有用。

  受篇幅限制,下一篇具體介紹locks包下類的使用。

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