2011-04-13 122 views
0

我正在學習帶有鎖的同步塊。我想知道這個鎖和程序中提供的某個第三方鎖之間的區別。同步塊上的Java線程鎖

public class NewThread extends Thread { 
StringBuffer sb; 
NewThread(StringBuffer sb){ 
    this.sb=sb; 
} 
public void run(){ 
    synchronized(this.sb){ 
     for(int i=0;i<1000;i++){ 
      System.out.print(sb); 
       try{ 
      Thread.sleep(5*60); 
     } 
     catch(Exception e){} 
     } 
     char c = this.sb.charAt(0); 
     this.sb.setCharAt(0, ++c); 
    } 
} 
public static void main(String[] args){ 
    StringBuffer sb=new StringBuffer("A"); 
    NewThread nt=new NewThread(sb); 
    NewThread nt1=new NewThread(sb); 
    NewThread nt2=new NewThread(sb); 
    nt.start(); 
    nt1.start(); 
    nt2.start(); 
} 

}

如果我打算把

public void run(){ 
    synchronized(this){ 
     for(int i=0;i<1000;i++){ 
      System.out.print(sb); 
       try{ 
      Thread.sleep(5*60); 
     } 
     catch(Exception e){} 
     } 
     char c = this.sb.charAt(0); 
     this.sb.setCharAt(0, ++c); 
    } 
} 

這裏在上面運行方法我在synchronized塊給這個......我希望他們

之間的區別

我還有一個問題,如果我們在同步塊中給出鎖對象,並且我們沒有在該塊內使用該對象,那麼我們是否會觀察到與正常塊相比的任何特定事物

回答

4

如果您具有一般OS API的併發開發經驗,例如在Linux中的pthread庫中,您可能已經知道我們應該使用鎖定或其他數據結構來同步訪問關鍵部分(共享對象可能會被修改)的進程/線程。

Java使用鎖來實現同步塊。同步塊是一種機制(稱爲操作系統中的監視器),封裝了與鎖有關的繁瑣操作。每個對象在java中都有一個鎖。在同步時,首先鎖定共享對象(也可以說其他進程需要共享對象的鎖定)。如果某個線程無法獲得該鎖,那意味着其他某個線程現在持有鎖,它必須等到其他線程釋放該鎖並再次重新獲取,直到它鎖定該鎖並進入關鍵部分。

第一個代碼片段在StringBuffer實例中使用lock,即sb,每個線程都會嘗試獲取sb的鎖(在運行代碼之前調用lock_of_sb.lock(),只有成功獲取sb的鎖才能最終執行代碼。

至於第二個碼,這相當於

public synchronized void run(){ 
    for(int i=0;i<1000;i++){ 
     System.out.print(sb); 
     try{ 
     Thread.sleep(5*60); 
    } 
    catch(Exception e){} 
    } 
    char c = this.sb.charAt(0); 
    this.sb.setCharAt(0, ++c); 
} 

我不認爲它的行爲如你預期它在這個對象獲取鎖,但是,此對象永遠不會共享,所以共享sb在沒有任何同步的情況下暴露在關鍵部分中

該鏈接將爲您提供另一種實現同步的工作方式。 How to synchronize static method in java雖然問題本身是關於靜態方法的,但它也適用於實例成員方法。

+0

謝謝我的理解..但我沒有得到共享鎖或共享鎖..可以解釋一下 – satheesh 2011-04-13 05:01:41

+0

@satheesh我不知道這是你想要的:在一個同步的多線程/進程系統中,通常只有一種資源可以存在一個鎖。它用於控制共享對象。在Linux中,鎖和共享對象是分開的。在Java中,每個對象都有自己的鎖(可以在類Object的源代碼中找到)。也許在linux中,我們可以說一個鎖被一些進程共享,因爲鎖和進程/線程之間沒有關係。但在Java中,由於每個對象都有自己的鎖,因此不需要明確地共享鎖。該鎖由對象隱式維護。隨意問。 – 2011-04-13 05:15:15

+0

確定我明白..但是每一個你與Linux有關的事情,我有點困惑 – satheesh 2011-04-13 05:40:39

2

在Java中,每個對象都可以用作互斥鎖(請參閱Mutual Exclusion)。這意味着在任何時候只有一件事物可以同步在一個對象上,你使用的對象通常是不敬的,儘管它應該儘可能具體。例如,如果多個線程正在訪問List,則應該在該列表上而不是在整個對象上同步(this),以便其他需要對象中的其他內容可以訪問它的東西。

我認爲關於互斥的文章可能有助於澄清此事。實質上,只有一個線程可能會獲得「鎖定」的密鑰 - 該鎖定是同步內部的。只要訪問您的資源的所有內容都請求SAME對象上的鎖,您就會受到保護。

+0

好的解釋! – slezica 2011-04-13 04:33:08

+0

如果你不知道我可以解釋有關我給出的例子...... – satheesh 2011-04-13 04:33:35

+0

Satheesh,你的例子僅在它們鎖定的對象上有所不同。在第一個示例(this.sb)中 - 所有這一切意味着一次只有一個線程可以位於同步(this.sb)塊內。你的第二個例子意味着只有一個線程可以位於synchronized(this){}塊內。使用哪一個取決於 - 你想要阻止線程同時訪問ENTIRE對象,或者只是字符串緩衝區? – Ben 2011-04-13 04:46:02

3

其他人已經回答了,但增加我的2美分,

一)第一個例子是確定的,在這個意義上,​​關鍵字守着StringBuffer線程共享一個鎖。

b)第二實施例是不正常。你給每個線程一個不同的鎖。實際上,它沒有任何效果(事實上,現代Java編譯器完全移除了這種鎖)。如果多個線程使用它,則鎖定是有意義的。

你可以這樣想:
如果你共用一間浴室,你最好有一把鎖的浴室(如門鑰匙)。如果您在使用浴室之前要求所有人鎖定他們自己的個人iPhone,那肯定沒用。請注意,共享外觀不需要成爲門鑰匙。你可能會以及挑選一個iPhone,並把它作爲浴室的「鑰匙」(每個人都有使用的廁所,只有誰鎖定它可以解鎖的傢伙之前鎖定 iPhone)。在現實生活中,這聽起來很荒謬,但這與我們用互斥體做的很相似。

c)第二個例子可以被認爲是越野車,但實際上,你不會看到競爭條件的影響。這是因爲StringBuffer內部同步。如果您使用StringBuilder相反,你可能能夠看到競態條件(取決於運行條件)。

+0

+1指出StringBuffer是線程安全的。 – 2011-04-13 05:48:29