java多線程關鍵字volatile、lock、synchronized

一、volatile

volatile寫和volatile讀的內存語義:

線程A寫一個volatile變量,實質上是線程A向接下來將要讀這個volatile變量的某個線程發(fā)出了(其對共享變量所在修改的)消息。

線程B讀一個volatile變量,實質上是線程B接收了之前某個線程發(fā)出的(在寫這個volatile變量之前對共享變量所做修改的)消息。

線程A寫一個volatile變量,隨后線程B讀這個volatile變量,這個過程實質上是線程A通過主內存向線程B發(fā)送消息。

鎖釋放和鎖獲取的內存語義:

線程A釋放一個鎖,實質上是線程A向接下來將要獲取這個鎖的某個線程發(fā)出了(線程A對共享變量所做修改的)消息。

線程B獲取一個鎖,實質上是線程B接收了之前某個線程發(fā)出的(在釋放這個鎖之前對共享變量所做修改的)消息。

線程A釋放鎖,隨后線程B獲取這個鎖,這個過程實質上是線程A通過主內存向線程B發(fā)送消息。

總結:volatile關鍵字的作用是:使變量在多個線程間可見(具有可見性),但是僅靠volatile是不能保證線程的安全性,volatile關鍵字不具備synchronized關鍵字的原子性。

二、lock

Lock是一個接口:

publicinterfaceLock {

????voidlock();

????voidlockInterruptibly()?throwsInterruptedException;

????booleantryLock();

????booleantryLock(longtime, TimeUnit unit)?throwsInterruptedException;

????voidunlock();

????Condition newCondition();

}

lock()、tryLock()、tryLock(long time, TimeUnit unit)和lockInterruptibly()是用來獲取鎖的。unLock()方法是用來釋放鎖的。

tryLock()方法是有返回值的,它表示用來嘗試獲取鎖,如果獲取成功,則返回true,如果獲取失敗(即鎖已被其他線程獲?。瑒t返回false,也就說這個方法無論如何都會立即返回。在拿不到鎖時不會一直在那等待。

tryLock(long time, TimeUnit unit)方法和tryLock()方法是類似的,只不過區(qū)別在于這個方法在拿不到鎖時會等待一定的時間,在時間期限之內如果還拿不到鎖,就返回false。如果如果一開始拿到鎖或者在等待期間內拿到了鎖,則返回true。

lockInterruptibly()方法比較特殊,當通過這個方法去獲取鎖時,如果線程正在等待獲取鎖,則這個線程能夠響應中斷,即中斷線程的等待狀態(tài)。也就使說,當兩個線程同時通過lock.lockInterruptibly()想獲取某個鎖時,假若此時線程A獲取到了鎖,而線程B只有在等待,那么對線程B調用threadB.interrupt()方法能夠中斷線程B的等待過程。

lock在獲取鎖的過程可以被中斷。

lock可以嘗試獲取鎖,如果鎖被其他線程持有,則返回 false,不會使當前線程休眠。

lock在嘗試獲取鎖的時候,傳入一個時間參數,如果在這個時間范圍內,沒有獲得鎖,那么就是終止請求。

synchronized 會自動釋放鎖,lock 則不會自動釋放鎖。

注:lock() 可以用于對一段代碼進行加鎖,這樣別的代碼在鎖釋放之前需要進行等待,需要注意,lock不會像 synchronized 那樣自動釋放鎖,所以:一定要放在 try-finally塊中,保證鎖的釋放。

Lock和synchronized有以下幾點不同:

  1)Lock是一個接口,而synchronized是Java中的關鍵字,synchronized是內置的語言實現;

  2)synchronized在發(fā)生異常時,會自動釋放線程占有的鎖,因此不會導致死鎖現象發(fā)生;而Lock在發(fā)生異常時,如果沒有主動通過unLock()去釋放鎖,則很可能造成死鎖現象,因此使用Lock時需要在finally塊中釋放鎖;

  3)Lock可以讓等待鎖的線程響應中斷,而synchronized卻不行,使用synchronized時,等待的線程會一直等待下去,不能夠響應中斷;

  4)通過Lock可以知道有沒有成功獲取鎖,而synchronized卻無法辦到。

  5)Lock可以提高多個線程進行讀操作的效率。

  在性能上來說,如果競爭資源不激烈,兩者的性能是差不多的,而當競爭資源非常激烈時(即有大量線程同時競爭),此時Lock的性能要遠遠優(yōu)于synchronized。所以說,在具體使用時要根據適當情況選擇。

ReentrantLock,意思是“可重入鎖”,關于可重入鎖的概念在下一節(jié)講述。ReentrantLock是唯一實現了Lock接口的類,并且ReentrantLock提供了更多的方法。

三、synchronized

? ?1、當兩個并發(fā)線程訪問同一個對象object中的這個synchronized(this)同步代碼塊時,一個時間內只能有一個線程得到執(zhí)行。另一個線程必須等待當前線程執(zhí)行完這個代碼塊以后才能執(zhí)行該代碼塊。

2、然而,當一個線程訪問object的一個synchronized(this)同步代碼塊時,另一個線程仍然可以訪問該object中的非synchronized(this)同步代碼塊。

3、尤其關鍵的是,當一個線程訪問object的一個synchronized(this)同步代碼塊時,其他線程對object中所有其它synchronized(this)同步代碼塊的訪問將被阻塞。

? ? ?4、第三個例子同樣適用其它同步代碼塊。也就是說,當一個線程訪問object的一個synchronized(this)同步代碼塊時,它就獲得了這個object的對象鎖。結果,其它線程對該object對象所有同步代碼部分的訪問都被暫時阻塞。

synchronized關鍵字的作用域:

某個對象實例內,synchronized aMethod(){}可以防止多個線程同時訪問這個對象的synchronized方法(如果一個對象有多個synchronized方法,只要一個線 程訪問了其中的一個synchronized方法,其它線程不能同時訪問這個對象中任何一個synchronized方法)。這時,不同的對象實例的 synchronized方法是不相干擾的。也就是說,其它線程照樣可以同時訪問相同類的另一個對象實例中的synchronized方法;

某個類的范圍,synchronized static aStaticMethod{}防止多個線程同時訪問這個類中的synchronized static 方法。它可以對類的所有對象實例起作用。

------------------------------------------------------------------------------------------------------------------------------

本文來自 旭日Follow_24 的CSDN 博客 ,全文地址請點擊:https://mp.csdn.net/postedit/80953306

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容