閱讀29 返回首頁    go 技術社區[雲棲]


哪個對象才是鎖?

我們都知道當一個線程試圖訪問同步代碼塊時,它首先必須得到鎖,退出或拋出異常時必須釋放鎖。這些基礎也許大家都知道,但是很多人還是搞不清哪個對象才是鎖?如果你能正確回答以下問題,那麼才算你徹底搞明白了哪個對象才是鎖?

靜態同步方法問題

如下代碼是兩個靜態同步方法


Class A{

public static synchronized void write(boolean b){
  isTrue = b;
}

public static synchronized boolean read(){
  return isTrue;
}
}

那麼我們來問幾個問題

  1. 線程1訪問A.write(true)方法時,線程2能訪問A.read()方法嗎?
  2. 線程1訪問new A().write(false)方法時,線程2能訪問new A().read()方法嗎?
  3. 線程1訪問A.write(false)方法時,線程2能訪問new A().read()方法嗎?

實例同步方法問題

如下代碼是兩個實例同步方法


public synchronized void write(boolean b){
  isTrue = b;
}

public synchronized boolean read(){
  return isTrue;
}

同樣問兩個問題:

  1. A a=new A(); 線程1訪問a.write(false)方法,線程2能訪問a.read()方法嗎?
  2. A a=new A(); A b=new A();線程1訪問a.write(false)方法,線程2能訪問b.read()方法嗎?

回答問題之前,先想一下當前方法使用的鎖是哪一個?當前線程是否有拿到這把鎖?拿到鎖了就能訪問當前方法了。

答案

我們先回顧基礎知識,Java中的每一個對象都可以作為鎖,而不同的場景鎖是不一樣的。

  1. 對於實例同步方法,鎖是當前實例對象。
  2. 對於靜態同步方法,鎖是當前對象的Class對象。
  3. 對於同步方法塊,鎖是Synchonized括號裏配置的對象。

線程1訪問A.write()方法時,線程2能訪問A.read()方法嗎?不能,因為靜態方法的鎖都是A.Class對象,線程1拿到鎖之後,線程2就拿不到鎖了。

線程1訪問new A().write()方法時,線程2能訪問new A().read()方法嗎?不能,原因同上。

線程1訪問A.write()方法時,線程2能訪問new A().read()方法嗎?不能,原因同上

A a=new A(); 線程1訪問a.write()方法,線程2能訪問a.read()方法嗎?不能,因為這兩個方法的鎖都是對象a,線程1拿到了鎖,線程2就不能訪問了。

A a=new A(); A b=new A();線程1訪問a.write()方法,線程2能訪問b.read()方法嗎?可以,因為線程1拿到的是鎖是 a,而線程2訪問b.read()需要的是鎖是b。

現在你應該明白了這句話,對於實例同步方法,鎖是當前實例對象。對於靜態同步方法,鎖是當前對象的Class對象


文章轉自 並發編程網-ifeve.com

最後更新:2017-05-23 11:02:49

  上一篇:go  深入理解Java內存模型(一)——基礎
  下一篇:go  False Sharing