關于synchronized、volatile、ReentrantLock的區(qū)別與對比
聊之前先說一下并發(fā)編程的3個特性。
并發(fā)編程特性
- 原子性:對共享資源的一組操作,要么成功要么失敗,不會出現(xiàn)部分成功部分失敗的情況。
- 可見性: 當線程獲取到瑣時,會拷貝一份共享資源到本地內(nèi)存,釋放鎖時會將共享資源刷新到主內(nèi)存中。可見性是指當共享資源發(fā)生變化時,其他線程都能夠看到這個變化。
- 有序性:為了提高效率,編譯器和處理器會對代碼進行指令重排,單線程的情況下,指令重拍不會受到影響,多線程情況下可能會影響代碼執(zhí)行的正確性。有序性是指代碼編寫順序和執(zhí)行順序是一致的。
volatile
volatile 是JVM提供的最輕量級的同步機制,編譯器不會對其進行優(yōu)化。
特性:
- volatile 只保證共享資源的可見性和有序性。
- 使用volatile修飾共享資源時,如果共享資源變化時,會直接將緩存中的數(shù)據(jù)寫回到主內(nèi)存中去,數(shù)據(jù)也是從主內(nèi)存中讀取,從而保證了可見性。
- volatile 底層是通過操作系統(tǒng)的內(nèi)存屏障來實現(xiàn)的,由于使?了內(nèi)存屏障,所以會禁?指令重排,從而就保證了有序性。
作用的地方:
volatile 只能用來修飾成員變量。
public class VolatileTest { private volatile static String staticVolatile; private volatile String memberVolatile; }
synchronized
synchronized關鍵字是java提供的內(nèi)置鎖來保證我們對共享資源的同步,它會自動加鎖和釋放鎖,它的鎖是非公平鎖, synchronized關鍵字標記的地方會被編譯器進行優(yōu)化。synchronized會使線程串行執(zhí)行,可能會造成線程阻塞。
特性
- synchronized關鍵字使線程串行化執(zhí)行,所以保證了并發(fā)安全的3個特性,并且還擁有以下兩個特性:
- 互斥性:同時只有一個線程能夠訪問synchronized方法或者同步代碼塊。
- 可重入性:synchronized是可重入鎖,通俗解釋可重入鎖就是當一個線程獲取到了某個對象鎖或者類鎖之后,這個線程在未釋放鎖之前,再調(diào)用該鎖的其他synchronized方法或代碼塊時,不用再次重新獲得鎖。
作用的地方
synchronized關鍵字可用來修飾方法或者代碼塊。
修飾方法,分為實例方法和靜態(tài)方法
- 修飾實例方法,對象鎖
public synchronized void objectMethods(){ ..... }
- 修飾靜態(tài)方法,類鎖
public static synchronized void staticMethods(){ ..... }
修飾代碼塊
obj為對象的引用 對象鎖
public void objectMethods(){ synchronized (obj){ } }
Object 為某個類 類鎖
public void classLock(){ synchronized (Object.class){ } }
ReentrantLock
Lock 是 Java 5提供的一個具有鎖機制的接口,ReentrantLock 是Lock的一個實現(xiàn),內(nèi)部是通過AQS(AbstractQueuedSynchronizer)實現(xiàn)的。ReentrantLock翻譯過來是可重入鎖,它和synchronized類似,ReentrantLock 需要手動加鎖和釋放鎖, 相對于synchronized它更加靈活,提供了更多的方法。 ReentrantLock 有公平鎖和非公平鎖兩種方式,默認是使用公平鎖。
特性
ReentrantLock 是可重入的同步鎖,所以它除了具有并發(fā)編程的三大特性,還具有可重入性。
作用的地方
ReentrantLock 是一個類,它既可以作為成員變量,也可以作為局部變量使用。做為成員變量和局部變量時,使用的方式有一點點不同,不管使用哪種方式,最后都別忘了要調(diào)用unlock()
方法手動釋放鎖。
做為成員變量使用格式:
private Lock globalLock = new ReentrantLock(); public void globalLock(){ if (globalLock.tryLock()) { try { } catch (Exception e) { }finally { globalLock.unlock(); } } }
上面的tryLock()
方法是嘗試獲取鎖,如果獲取成功返回true,否則返回false,也可以換成加了等待時間的 boolean tryLock(long time, TimeUnit unit)
方法,在設定的等待時間內(nèi)獲取鎖成功則返回true,否則false。
做為局部變量使用格式:
public void lock(){ Lock lock = new ReentrantLock(); lock.lock(); try { }finally { lock.unlock(); } }
對比
簡單對比一下三者之間的區(qū)別:
volatile | synchronized | ReentrantLock | |
是否是關鍵字 | 是 | 是 | 否 |
是否需要手動加鎖/釋放鎖 | 否 | 否 | 是 |
是否能保證并發(fā)安全 | 否 | 是 | 是 |
是否是公平鎖 | \ | 否 | 有公平鎖和非公平鎖兩種實現(xiàn) |
是否會阻塞線程 | 否 | 是 | 是 |
JVM是否會對其優(yōu)化 | 否 | 是 | 否 |
特性 | 可見性、有序性 | 可見性、有序性、原子性 | 可見性、有序性、原子性 |
使用的地方 | 成員變量 | 方法、代碼塊 | 成員變量、局部變量 |
到此這篇關于關于synchronized、volatile、ReentrantLock的區(qū)別與對比的文章就介紹到這了,更多相關synchronized、volatile、ReentrantLock的區(qū)別內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
java中FileOutputStream中文亂碼問題解決辦法
這篇文章主要介紹了java中FileOutputStream中文亂碼問題解決辦法的相關資料,需要的朋友可以參考下2017-04-04Java中執(zhí)行docker命令的實現(xiàn)示例
本文主要介紹了Java中執(zhí)行docker命令的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2023-08-08使用maven-assembly-plugin如何打包多模塊項目
這篇文章主要介紹了使用maven-assembly-plugin如何打包多模塊項目,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03mybatis-plus的SafetyEncryptProcessor安全加密處理示例解析
這篇文章主要為大家介紹了mybatis-plus的SafetyEncryptProcessor安全加密處理示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-08-08Java import static及import原理區(qū)別解析
這篇文章主要介紹了Java import static及import原理區(qū)別解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-10-10