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