2011-10-18 37 views
1

我正在閱讀最初來自(我相信)IBM developerworks網站的線程教程。其中他們談到了synchronized關鍵字,以及同步代碼塊如何被實際對象鎖定,而不是代碼塊本身。在java中同步關鍵字和靜態類

例如,在作者下面的代碼說明的是,即使靜態類「ThingiesetLastAccess方法被列爲同步的,在它下面限定的兩個線程可以每個呼叫setLastAccess同時,因爲他們使用不同的值對於thingie。但是如果thingie是靜態的,那不就意味着它們使用了相同的值嗎?

這種情況下,變量名稱只需要不同,即使它們指的是同一個對象?

public class SyncExample { 
    public static class Thingie { 
     private Date lastAccess; 
     public synchronized void setLastAccess(Date date) { 
      this.lastAccess = date; 
     } 
    } 
    public static class MyThread extends Thread { 
     private Thingie thingie; 
     public MyThread(Thingie thingie) { 
      this.thingie = thingie; 
     } 
     public void run() { 
      thingie.setLastAccess(new Date()); 
     } 
    } 
    public static void main() { 
     Thingie thingie1 = new Thingie(), 
     thingie2 = new Thingie(); 
     new MyThread(thingie1).start(); 
     new MyThread(thingie2).start(); 
    } 
} 
+1

我確定它不依賴於變量的名稱。同步的是對實際對象的調用,而不是變量。 –

+0

相關http://stackoverflow.com/questions/578904/how-do-synchronized-static-methods-work-in-java – Gray

+0

我的回答是否幫助你@larryq?如果是這樣,請接受它。 – Gray

回答

4

你混淆了一個靜態方法與靜態類。如果setLastAccess是一個靜態的方法那麼如果它被標記爲​​,它將鎖定在ClassLoader中的Class實例 - 每個加載程序只有一個這樣的實例。如果該方法是靜態的並且是同步的,那麼線程將鎖定在同一個對象上。

但是,在您的示例中,Thingie被標記爲靜態,而不是方法。 類別上的靜態關鍵字意味着Thingie未連接到外部SyncExample類 - 它確實是而不是意味着只有一個Thingie實例,並且它不影響同步。因此,在您的示例中,當setLastAccess標記爲​​時,它鎖定類Thingiethis)的實例。由於存在兩個實例(thingie1thingie2),因此這些鎖位於不同的對象上。顯然,如果兩個線程都通過thingie1,那麼它們都會鎖定在同一個對象上。

下面是一些閱讀:

+0

我很欣賞這個解釋。但是,考慮到Thingie是一個靜態類,是否可以有兩個實例(thingie1和thingie2)?如果沒有,那是不是意味着兩個(同步)調用setLastAccess()是從Thingie的同一個實例調用的? – larryq

+0

不知道你看過我的回答@larryq。 'static'關鍵字並不意味着一個實例。閱讀我的答案和上面的「嵌套類」鏈接中的第二段。 – Gray

+0

格雷 - 非常感謝澄清和鏈接。我之前對嵌套的靜態類表示的誤解。我認爲這意味着它是外部類的靜態成員(雖然是類),因此無法直接實例化 - 或者至少這樣做只會返回與外部類相關的一個實例。我錯了。 – larryq

3

此代碼:

class SomeClass { 
    public synchronized void setLastAccess(Date date) { 
    } 
} 

是一樣的:

class SomeClass { 
    public void setLastAccess(Date date) { 
     synchronized(this) { 
     } 
    } 
} 

而這種代碼:

class SomeClass { 
    public static synchronized void setLastAccess(Date date) { 
    } 
} 

是一樣的:

class SomeClass { 
    public static void setLastAccess(Date date) { 
     synchronized(SomeClass.class) { 
     } 
    } 
} 
0

如果同步方法是實例方法,則鎖定是在每個對象上完成的。所以如果你有2個對象obj1和obj2,他們可以用鎖定自己的實例來執行方法。

如果一個靜態方法是同步的,則在類對象上完成鎖定。因此,當第一個靜態同步方法得到執行時,該方法以及任何其他靜態方法都無法執行。