首頁  >  文章  >  Java  >  java多執行緒關鍵字volatile、lock以及synchronized的簡單介紹

java多執行緒關鍵字volatile、lock以及synchronized的簡單介紹

不言
不言原創
2018-09-25 15:36:101887瀏覽

這篇文章帶給大家的內容是關於java多線程關鍵字volatile、lock以及synchronized的簡單介紹,有一定的參考價值,有需要的朋友可以參考一下,希望對你有所幫助。

一、volatile

volatile寫和volatile讀的記憶體語義:

  線程A寫一個volatile變量,實質上是線程A向接下來將要讀這個volatile變數的某個執行緒發出了(其對共享變數所在修改的)訊息。線程B讀一個volatile變量,實質上是線程B接收了之前某個線程發出的(在寫這個volatile變量之前對共享變量所做修改的)訊息。線程A寫一個volatile變量,隨後線程B讀這個volatile變量,這個過程實質上是線程A透過主記憶體向線程B發送訊息。

鎖定釋放和鎖定獲取的記憶體語意:

  線程A釋放一個鎖,實質上是線程A向接下來將要獲取這個鎖的某個線程發出了(線程A對共享變數所做修改的)訊息。線程B取得一個鎖,實質上是線程B接收了之前某個線程發出的(在釋放這個鎖之前對共享變數所做修改的)訊息。線程A釋放鎖,隨後線程B取得這個鎖,這個過程實質上是線程A透過主記憶體向線程B發送訊息。

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

二、lock

   Lock是一個介面:

public interface Lock {  
   void lock();     
   void lockInterruptibly() throws InterruptedException;
    boolean tryLock();
    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
    void unlock();
    Condition newCondition();
}

lock()、tryLock()、tryLock(long time, TimeUnit unit)和lockInterruptibly()是用來取得鎖的。

unLock()方法是用來釋放鎖定的。 tryLock()方法是有回傳值的,它表示用來嘗試取得鎖,如果取得成功,則傳回true,如果取得失敗(即鎖已被其他執行緒取得),則傳回false,也就說這個方法無論如何都會立即返回。在拿不到鎖時不會一直在那裡等待。 tryLock(long time, TimeUnit unit)方法和tryLock()方法是類似的,只不過區別在於這個方法在拿不到鎖時會等待一定的時間,在時間期限之內如果還拿不​​到鎖,就返回false。如果如果一開始拿到鎖或在等待期間內拿到了鎖,則傳回true。 lockInterruptibly()方法比較特殊,當透過這個方法去取得鎖時,如果執行緒正在等待取得鎖,則這個執行緒能夠回應中斷,也就是中斷執行緒的等待狀態。也使說,當兩個執行緒同時透過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在發生異常時,會自動釋放線程佔有的鎖,因此不會導致死鎖現象發生;而Lock在發生異常時,如果沒有主動通過unLock()去釋放鎖,則很可能造成死鎖現象,因此使用Lock時需要在finally塊中釋放鎖;

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

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

  5)Lock可以提高多個執行緒進行讀取操作的效率。  在性能上來說,如果競爭資源不激烈,兩者的性能是差不多的,而當競爭資源非常激烈時(即有大量線程同時競爭),此時Lock的性能要遠遠優於synchronized。所以說,在具體使用時要根據適當情況選擇。 ReentrantLock,意思是“可重入鎖”,關於可重入鎖的概念在下一節中講述。 ReentrantLock是唯一實作了Lock介面的類,而ReentrantLock則提供了更多的方法。

三、synchronized

     1、當兩個並發執行緒訪問同一個物件object中的這個synchronized(this)同步程式碼區塊時,一個時間內只能有一個執行緒來執行。另一個執行緒必須等待目前執行緒執行完這個程式碼區塊以後才能執行該程式碼區塊。

     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 方法。它可以對類別的所有物件實例起作用。

以上是java多執行緒關鍵字volatile、lock以及synchronized的簡單介紹的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn