摘要:只有首先獲得鎖的任務(wù)線程才能繼續(xù)獲取該對象上的多個鎖。會進(jìn)一步對時失敗的那些線程進(jìn)行阻塞操作調(diào)用操作系統(tǒng)的信號量此段來摘自別處。提供了多樣化的同步,比如有時間限制的同步,可以被的同步的同步是不能的等。
各種方法
1?synchronized方法。
public synchronized void save(){}
2?synchronized代碼塊。
synchronized(object){ }
3?使用重入鎖(ReenreantLock)
public void save(int money) { lock.lock(); try { account += money; } finally { lock.unlock(); } }
4?使用阻塞隊列,同步Map(LinkedBlockingQueue,ConcurrentHashMap等)
5?使用原子變量(AtomicInteger等)
各種原理獨占鎖:是一種悲觀鎖,會導(dǎo)致其它所有需要鎖的線程掛起,等待持有鎖的線程釋放鎖。
樂觀鎖:每次不加鎖,假設(shè)沒有沖突就去完成某項操作,如果因為沖突失敗就重試,直到成功為止。
CAS:Compare and Swap,典型的樂觀鎖,使用Cpu的lock cmpxchg指令進(jìn)行操作。CAS的底層類為Unsafe,Unsafe通過調(diào)用JNI(Java Native Interface)代碼,在C語言的compareAndSwapInt函數(shù)中嵌入?yún)R編指令進(jìn)行實現(xiàn),做到了處理器級別的同步。java.util.concurrent包的所有類都基于CAS。
注:volatile保證可見性。參見https://segmentfault.com/a/11...
CAS也有幾個缺點:
總結(jié):1?ABA問題,由AtomicStampedReference來解決,即給數(shù)據(jù)加版本信息。
2?循環(huán)時間長開銷大。
3?只能保證一個共享變量的原子操作,由AtomicReference來解決,即將多個基本變量整合為一個對象。
synchronized:
所有對象都自動含有單一的鎖,JVM負(fù)責(zé)跟蹤對象被加鎖的次數(shù)。如果一個對象被解鎖,其計數(shù)變?yōu)?。在任務(wù)(線程)第一次給對象加鎖的時候,計數(shù)變?yōu)?。每當(dāng)這個相同的任務(wù)(線程)在此對象上獲得鎖時,計數(shù)會遞增。只有首先獲得鎖的任務(wù)(線程)才能繼續(xù)獲取該對象上的多個鎖。每當(dāng)任務(wù)離開時,計數(shù)遞減,當(dāng)計數(shù)為0的時候,鎖被完全釋放。synchronized就是基于這個原理,同時synchronized靠某個對象的單一鎖技術(shù)的次數(shù)來判斷是否被鎖,所以無需(也不能)人工干預(yù)鎖的獲取和釋放。
實際上synchronized作用于方法時,鎖住的是“this”,作用于靜態(tài)方法/屬性時,鎖住的是存在于永久帶的CLASS,相當(dāng)于這個CLASS的全局 鎖,鎖作用于一般對象時,鎖住的是對應(yīng)代碼塊。在HotSpot中JVM實現(xiàn)中,鎖有個專門的名字:對象監(jiān)視器。
jdk1.6之前,synchronized是通過對象內(nèi)部的一個叫做監(jiān)視器鎖(monitor)來實現(xiàn)的。但是監(jiān)視器鎖本質(zhì)又是依賴于底層的操作系統(tǒng)的Mutex Lock來實現(xiàn)的。而操作系統(tǒng)實現(xiàn)線程之間的切換這就需要從用戶態(tài)轉(zhuǎn)換到核心態(tài),這個成本非常高,狀態(tài)之間的轉(zhuǎn)換需要相對比較長的時間,這就是為什么Synchronized效率低的原因。然而,1.6之后,synchronized已經(jīng)被做了CAS的優(yōu)化:具體是這樣的,當(dāng)執(zhí)行到synchronized代碼塊時,先對對象頭的鎖標(biāo)志位用lock cmpxchg的方式設(shè)置成“鎖住“狀態(tài),釋放鎖時,在用lock cmpxchg的方式修改對象頭的鎖標(biāo)志位為”釋放“狀態(tài),寫操作都立刻寫回主內(nèi)存。JVM會進(jìn)一步對synchronized時CAS失敗的那些線程進(jìn)行阻塞操作(調(diào)用操作系統(tǒng)的信號量)(此段來摘自別處)。也就是先CAS操作,不行的話繼而阻塞線程。
ReentrantLock:
Lock不同于synchronized面向?qū)ο?,它基于棧中的框架而不是某個具體對象,所以Lock只需要在棧里設(shè)置鎖的開始和結(jié)束 (lock和unlock)的地方就行了(人工必須標(biāo)明),不用關(guān)心框架大小對象的變化等等。這么做的好處是Lock能提供無條件的、可輪詢的、定時的、 可中斷的鎖獲取操作,相對于synchronized來說,synchronized的鎖的獲取是釋放必須在一個模塊里,獲取和釋放的順序必須相反,而Lock則可以在不同范圍內(nèi)獲取釋放,并且順序無關(guān)。
ReentrantLock提供了多樣化的同步,比如有時間限制的同步,可以被Interrupt的同步(synchronized的同步是不能Interrupt的)等。lock是通過代碼實現(xiàn)的,要保證鎖一定會被釋放,就必須將unlock()放到finally{}中。
最后,Atomic無疑是最快的,其次是ConcurrentHashMap等。在較高的并發(fā)下,幾種方法性能差不多,而在較低并發(fā)下,區(qū)別就顯現(xiàn)出來了,其中synchronized比Lock來的快,基本是兩倍的關(guān)系。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/67020.html
摘要:的關(guān)鍵字中的塊使用關(guān)鍵字進(jìn)行標(biāo)記。由于每個類只有一個類對象存在于中,因此全局同時只有一個線程能夠進(jìn)入到同一個類的靜態(tài)同步方法中。同步代碼塊使這種期望成為可能。注意同步代碼塊如何在括號中接受一個對象。相同的實例被傳入兩個不同的線程實例中。 Java的synchronized塊標(biāo)記一個方法或一個代碼塊為同步的。synchronized塊能用于防止出現(xiàn)競態(tài)條件。 Java的synchroni...
摘要:多線程和并發(fā)問題是技術(shù)面試中面試官比較喜歡問的問題之一。線程可以被稱為輕量級進(jìn)程。一個守護(hù)線程是在后臺執(zhí)行并且不會阻止終止的線程。其他的線程狀態(tài)還有,和。上下文切換是多任務(wù)操作系統(tǒng)和多線程環(huán)境的基本特征。 多線程和并發(fā)問題是 Java 技術(shù)面試中面試官比較喜歡問的問題之一。在這里,從面試的角度列出了大部分重要的問題,但是你仍然應(yīng)該牢固的掌握J(rèn)ava多線程基礎(chǔ)知識來對應(yīng)日后碰到的問題。(...
摘要:線程可以被稱為輕量級進(jìn)程。一個守護(hù)線程是在后臺執(zhí)行并且不會阻止終止的線程。其他的線程狀態(tài)還有,和。上下文切換是多任務(wù)操作系統(tǒng)和多線程環(huán)境的基本特征。在的線程中并沒有可供任何對象使用的鎖和同步器。 原文:Java Multi-Threading and Concurrency Interview Questions with Answers 翻譯:并發(fā)編程網(wǎng) - 鄭旭東 校對:方騰飛 多...
摘要:死亡狀態(tài)線程退出有可能是正常執(zhí)行完成也有可能遇見異常退出。類有新建與死亡狀態(tài)返回其余狀態(tài)返回判斷線程是否存活。線程因某些原因進(jìn)入阻塞狀態(tài)。執(zhí)行同步代碼塊的過程中執(zhí)行了當(dāng)前線程放棄開始睡眠進(jìn)入就緒狀態(tài)但是不會釋放鎖。 【java內(nèi)存模型簡介 JVM中存在一個主存區(qū)(Main Memory或Java Heap Memory),Java中所有變量都是存在主存中的,對于所有線程進(jìn)行共享,而每個...
閱讀 2040·2023-04-26 02:15
閱讀 2309·2021-11-19 09:40
閱讀 1051·2021-10-27 14:13
閱讀 3322·2021-08-23 09:44
閱讀 3622·2019-12-27 12:24
閱讀 661·2019-08-30 15:53
閱讀 1175·2019-08-30 10:53
閱讀 2167·2019-08-26 12:14