2011-06-16 100 views

回答

63

花費的時間我會嘗試添加一個例子來使這個額外的清晰。

如前所述,在Java中同步是Monitor概念的實現。當您將一段代碼標記爲已同步時,您使用一個對象作爲參數。當正在執行的線程來到這樣的代碼塊時,它必須先等待,直到同一對象上的同步塊中沒有其他正在執行的線程。

Object a = new Object(); 
Object b = new Object(); 
... 
synchronized(a){ 
    doStuff(); 
} 
... 
synchronized(b){ 
    doSomeStuff(); 
} 
... 
synchronized(a){ 
    doOtherStuff(); 
} 

在上述例子中,運行doOtherStuff(線程)將阻止另一個線程進入的代碼保護doStuff塊()。然而,一個線程可以在doSomeStuff()周圍進入塊而沒有問題,因爲它在對象b上同步,而不是對象a。

當您在實例方法(非靜態方法)上使用synchronized修飾符時,它與使用「this」作爲參數的同步塊非常相似。因此,在下面的例子中,了methodA()和的methodB()將採取同樣的方式:

public synchronized void methodA() { 
    doStuff(); 
} 
... 
public void methodB() { 
    synchronized(this) { 
     doStuff(); 
    } 
} 

請注意,如果你有一個methodC(),其中不同步,沒有同步塊類,沒有什麼會阻止線程進入該方法,粗心的編程可能會讓該線程訪問對象中的非安全代碼。

如果有與同步修飾符一個靜態方法,它是幾乎同樣的事情爲具有ClassName.class同步塊作爲參數(如果有類,ClassName cn = new ClassName();的目的,就可以訪問該對象與Class c = cn.getClass();

class ClassName { 
    public void static synchronized staticMethodA() { 
    doStaticStuff(); 
    } 
    public static void staticMethodB() { 
    synchronized(ClassName.class) { 
     doStaticStuff(); 
    } 
    } 
    public void nonStaticMethodC() { 
    synchronized(this.getClass()) { 
     doStuff(); 
    } 
    } 
    public static void unSafeStaticMethodD() { 
    doStaticStuff(); 
    } 
} 

因此,在上面的例子中,staticMethodA()和staticMethodB()動作相同的方式。執行線程也將被阻止訪問nonStaticMethodC()中的代碼塊,因爲它正在同一個對象上進行同步。

但是,重要的是要知道沒有任何東西會阻止正在執行的線程訪問unSafeStaticMethodD()。即使我們說靜態方法「在Class對象上同步」,但並不意味着它將所有訪問同步到該類中的方法。它僅僅意味着它使用Class對象進行同步。非安全訪問仍然是可能的。

+0

偉大的答案和偉大的工作解釋清楚的例子 – emilebaizel 2013-08-21 18:59:14

15

簡而言之,如果您在靜態方法上進行同步,您將在類(對象)上進行同步,而不是在實例(對象)上進行同步。這意味着執行靜態方法時,整個類都被阻塞。所以其他靜態同步方法也被阻塞。

+1

...如果它們也是同步的。 – Kaj 2011-06-16 06:49:57

+0

這是正確和編輯 – PeterMmm 2011-06-16 06:58:04

4

Java中的同步基本上是monitors的實現。在同步非靜態方法時,監視器屬於實例。在靜態方法上進行同步時,監視器屬於該類。同步代碼塊的想法是一樣的,但是監視器屬於指定的對象。如果你能擺脫它,同步塊是最好的,因爲它們最大限度地減少了每個線程在critical section

+2

只是爲了改善它:對於靜態方法,監視器屬於'Class'實例,而不是「* class *」。順便說一句 - 這是非常重要的,如果你必須使用多於一個類加載器,然後一個類加載器實際上加載相同的類 - 那麼我們有同一類的多個Class類實例... – 2011-06-16 06:58:40

+0

@Andreas_D謝謝你澄清。我並沒有意識到多班裝載機的細微差別。 – jpm 2011-06-16 07:01:01

3

同步塊和同步方法幾乎沒有區別。基本上:

void synchronized m() {...} 

相同

void m() { synchronized(this) {...} } 

通過比較靜態同步方法是一樣的:

static void m() { synchronized(MyClass.class) {...} } 
0

哥們,只是一個提示。不相關的問題:

如果做任何東西*()方法,並任

this.a= /*yet another*/ new Object(); 

this.b= /*yet another*/ new Object(); 

那麼你就完了。因爲鎖在該值內,而不在參考內。看到當它進入一個實例同步Java方法並且當它進入靜態同步的java方法獲取 類級鎖Java synchronized references

0

Java線程獲取對象級鎖。 通過使用同步塊您只能鎖定代碼的關鍵部分,並避免鎖定可能會降低性能的整個方法。