2010-08-11 28 views
2

我會嘗試通過以下三種情況來解釋這個問題。 案例一: 我是用使用這樣的同步共享鎖:使用本地鎖而不是共享鎖進行同步安全嗎?


     private static final String SHARED_LOCK = "shared_lock"; 
     private static int i = 0; 
     private static int j = 0; 
    void increment() { 
     synchronized (SHARED_LOCK) { 
      i++; 
      j++; 
     } 
    } 

而且這是工作的罰款。

案例二: 現在我已經在這改變是不是使用共享鎖,我做這樣的事情想使用本地鎖:


     private static int i = 0; 
     private static int j = 0; 
    void increment() { 
     final String LOCAL_LOCK = "local_lock"; 
        synchronized (LOCAL_LOCK) { 
      i++; 
      j++; 
     } 
    } 

而且我發現代碼仍然是工作罰款是同步仍在工作。

案例三: 然而,當我改變了當地LOCL這樣:

final String LOCAL_LOCK = new String("local_lock");

然後同步走了。所以看起來在CASE II中,本地鎖能夠提供同步,因爲Java會爲我們自動執行String實例,但是在CASE III中,我每次都明確地創建一個新的String,因此沒有發生同步。

所以回到我原來的問題。有沒有人認爲CASE II不是實現同步的正確方法?如果是的話,請你也提一下爲什麼?

在此先感謝, SacTiw。

回答

3

什麼是非常非常重要的這裏是用「canonicalizable」對象 - 公司,比如,String s,這可以被拘留,或Integer常量可以共享的 - 基本上是開放您使用相同的鎖定對象作爲另一個類。

正如你想象的那樣,這是一個非常糟糕的主意。通過使用與另一個類相同的鎖,您可以在以後嘗試並確定應用程序死鎖的原因時,基本上可以確保自己處於一個痛苦調試的整個世界。

如果您需要課堂上的私人鎖定,請確保它是完全唯一的對象,只能通過new運算符獲取。

(我相信Java的謎題演講可能已經覆蓋了這一之一;其他一些例子引用herehere

+0

所以在這裏你的意思是情況2可能會導致一些其他線程訪問其他類可能會開始使用相同的鎖作爲這個類,這將導致性能差和痛苦的調試。對? – sactiw 2010-08-12 09:57:12

+0

在Java語言規範中提到,在Java中,不同包中不同類中的文字字符串(不可變)同樣代表對同一個字符串對象的引用。這個規則適用於所有原始對象,因爲它們都是不可變的。 因此,這意味着如果我們按情況2行事,可能導致性能下降,並在面臨死鎖時進行痛苦的調試。 所以我認爲我可以說,我的問題可以通過案例2進行同步,但它並不是所有推薦的使用方式。 – sactiw 2010-08-12 14:24:19

+0

絕對,sactiw。使用除私有的,不可訪問的其他類對象以外的任何東西通常是一個非常糟糕的主意。如果你通過'new'得到一個對象,你就知道它是你自己的(只要你不泄漏它)。 – Cowan 2010-08-12 21:04:35

8

鎖是爲了在單獨的線程中運行的代碼之間提供同步。如果你使用本地鎖,每個線程將有自己的鎖對象副本(在線程的堆棧中),它將鎖定它,因此不會有同步。

它只適用於你的情況,因爲字符串interning。如果您使用final Object LOCAL_LOCK = new Object();則無法使用。

因此鎖應始終共享線程之間。

+0

+1實習。我們期望每次調用'increment()'都有自己的鎖,因爲它是一個局部變量。在這種情況下使用'String'是特殊的(導致同步意外工作),因爲VM爲所有變量使用相同的'String'實例,其中具有相同的文本。有關詳細信息,請參閱http://en.wikipedia.org/wiki/String_interning。 – f1sh 2010-08-11 10:23:14

+0

我知道爲什麼case-II能正常工作。我已經提到了在我的問題本身中由Java完成的String自動實習。我也知道爲什麼case-III失敗,因爲每個線程都有自己的鎖版本,所以他們等待其他線程完成。所以我真正感興趣的是知道是否使用案例II進行同步是非常安全的,還是存在後一種可能出現的案例II的一些隱藏問題。 – sactiw 2010-08-12 09:52:26

+0

@sactiw:如果你總是使用interned字符串作爲鎖,那麼它可能就沒問題。但是這仍然是一種不好的做法,因爲有一天有人可能會將字符串更改爲任何其他類型,並且一切都會神祕失敗。 – 2010-08-12 10:09:06

1

這是因爲字符串實習。如情況2中創建的所有字符串具有相同的值將「共享」相同的實例。如情況3中創建的字符串將是不同的實例。

正是這種差異說明了您所看到的不同步行爲。

4

只有在線程之間的同一對象上同步時,同步才能正確工作;

  • 第一種情況下是顯而易見的,
  • 在第二種情況下,Java編譯器實習生字符串常量這就是爲什麼它也能工作(你從電話之間的串池相同的對象),
  • 的第三種情況你強制一個新的字符串對象,因此你得到你自己的私人鎖定每個線程根本不同步。