【Java线程】线程同步—synchronized Lock
同步的實現當然是采用鎖了,java中使用鎖的兩個基本工具是 synchronized 和 Lock。
==========================================
synchronized
java語言的關鍵字,當它用來修飾一個方法或者一個代碼塊的時候,能夠保證在同一時刻最多只有一個線程執行該段代碼。
一、當兩個并發線程訪問同一個對象object中的這個synchronized(this)同步代碼塊時,一個時間內只能有一個線程得到執行。另一個線程必須等待當前線程執行完這個代碼塊以后才能執行該代碼塊。
二、然而,當一個線程訪問object的一個synchronized(this)同步代碼塊時,另一個線程仍然可以訪問該object中的非synchronized(this)同步代碼塊。
三、尤其關鍵的是,當一個線程訪問object的一個synchronized(this)同步代碼塊時,其他線程對object中所有其它synchronized(this)同步代碼塊的訪問將被阻塞。
四、第三個例子同樣適用其它同步代碼塊。也就是說,當一個線程訪問object的一個synchronized(this)同步代碼塊時,它就獲得了這個object的對象鎖。結果,其它線程對該object對象所有同步代碼部分的訪問都被暫時阻塞。
五、synchronized 用在方法和代碼塊上有什么區別呢?
synchronized 用在方法簽名上(以test為例),當某個線程調用此方法時,會獲取該實例的對象鎖,方法未結束之前,其他線程只能去等待。當這個方法執行完時,才會釋放對象鎖。其他線程才有機會去搶占這把鎖,去執行方法test,但是發生這一切的基礎應當是所有線程使用的同一個對象實例,才能實現互斥的現象。否則synchronized關鍵字將失去意義。但是如果該方法為類方法,即其修飾符為static,那么synchronized 意味著某個調用此方法的線程當前會擁有該類的鎖,只要該線程持續在當前方法內運行,其他線程依然無法獲得方法的使用權!
六、當線程運行到該代碼塊內,就會擁有obj對象的對象鎖,如果多個線程共享同一個Object對象,那么此時就會形成互斥!特別的,當obj == this時,表示當前調用該方法的實例對象。即
public void test() {
…
synchronized(this) {
// todo your code
}
…
}
此時,其效果等同于
public synchronized void test() {
// to do your code
}
使用synchronized代碼塊,可以只對需要同步的代碼進行同步,這樣可以大大的提高效率。
有關synchronized更詳細解析,請參看以下博客:
http://www.cnblogs.com/GnagWang/archive/2011/02/27/1966606.html
===========================================
Lock
1、Lock 實現提供了比使用 synchronized 方法和語句可獲得的更廣泛的鎖定操作。此實現允許更靈活的結構,可以具有差別很大的屬性,可以支持多個相關的 Condition 對象。
2、鎖是控制多個線程對共享資源進行訪問的工具。通常,鎖提供了對共享資源的獨占訪問。一次只能有一個線程獲得鎖,對共享資源的所有訪問都需要首先獲得鎖。不過,某些鎖可能允許對共享資源并發訪問,如 ReadWriteLock 的讀取鎖。
3、synchronized 方法或語句的使用提供了對與每個對象相關的隱式監視器鎖的訪問,但卻強制所有鎖獲取和釋放均要出現在一個塊結構中:當獲取了多個鎖時,它們必須以相反的順序釋放,且必須在與所有鎖被獲取時相同的詞法范圍內釋放所有鎖。
4、雖然 synchronized 方法和語句的范圍機制使得使用監視器鎖編程方便了很多,而且還幫助避免了很多涉及到鎖的常見編程錯誤,但有時也需要以更為靈活的方式使用鎖。例如,某些遍歷并發訪問的數據結果的算法要求使用 “hand-over-hand” 或 “chain locking”:獲取節點 A 的鎖,然后再獲取節點 B 的鎖,然后釋放 A 并獲取 C,然后釋放 B 并獲取 D,依此類推。Lock 接口的實現允許鎖在不同的作用范圍內獲取和釋放,并允許以任何順序獲取和釋放多個鎖,從而支持使用這種技術。
5、隨著靈活性的增加,也帶來了更多的責任。不使用塊結構鎖就失去了使用 synchronized 方法和語句時會出現的鎖自動釋放功能。在大多數情況下,應該使用以下語句:
Lock l = ...; l.lock();try {// access the resource protected by this lock} finally {l.unlock();}鎖定和取消鎖定出現在不同作用范圍中時,必須謹慎地確保保持鎖定時所執行的所有代碼用 try-finally 或 try-catch 加以保護,以確保在必要時釋放鎖。
6、Lock 實現提供了使用 synchronized 方法和語句所沒有的其他功能,包括提供了一個非塊結構的獲取鎖嘗試 (tryLock())、一個獲取可中斷鎖的嘗試 (lockInterruptibly()) 和一個獲取超時失效鎖的嘗試 (tryLock(long, TimeUnit))。
7、Lock 類還可以提供與隱式監視器鎖完全不同的行為和語義,如保證排序、非重入用法或死鎖檢測。如果某個實現提供了這樣特殊的語義,則該實現必須對這些語義加以記錄。
注意:
1、Lock 實例只是普通的對象,其本身可以在 synchronized 語句中作為目標使用。獲取 Lock 實例的監視器鎖與調用該實例的任何 lock() 方法沒有特別的關系。為了避免混淆,建議除了在其自身的實現中之外,決不要以這種方式使用 Lock 實例。
2、除非另有說明,否則為任何參數傳遞 null 值都將導致拋出 NullPointerException。
3、ReentrantLock 與synchronized有相同的并發性和內存語義,還包含了中斷鎖等候和定時鎖等候,意味著線程A如果先獲得了對象obj的鎖,那么線程B可以在等待指定時間內依然無法獲取鎖,那么就會自動放棄該鎖。但是由于synchronized是在JVM層面實現的,因此系統可以監控鎖的釋放與否,而ReentrantLock使用代碼實現的,系統無法自動釋放鎖,需要在代碼中finally子句中顯式釋放鎖lock.unlock();
相關實例請參看本人“線程協作”博客,鏈接如下:
http://blog.csdn.net/lmb55/article/details/46274165
總結:
各有千秋,在并發量比較小的情況下,使用synchronized是個不錯的選擇,但是在并發量比較高的情況下,其性能下降很嚴重,此時ReentrantLock是個不錯的方案。
總結
以上是生活随笔為你收集整理的【Java线程】线程同步—synchronized Lock的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Java线程】线程协作实现多对多聊天
- 下一篇: 【JFreeChart】JFreeCha