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