2010-06-23 113 views
3

我對對象鎖定有困惑。 下面的類有4個方法,方法addB()是同步的。同步使對象鎖定

在我的書架中,有4個主題。當一個線程訪問addB()方法(它在Test對象上創建一個鎖)時,會有其他線程訪問addC()或addD()的時間嗎?

對象鎖一次只允許一個線程嗎?

class Test{ 
     private Integer a; 
     private Integer b; 
     private Integer c; 
     private Integer d; 


    public void addA(){ 
     synchronized(a) { 
     a++; 
     } 
    } 
    public synchronized void addB(){ 
     b++; 
     } 

    public void addC(){ 
     c++; 
     } 

    public void addD(){ 
     d++; 
     }  
    } 

編輯: 我有3個線程(T1,T2和T3),並且每一個將要訪問ADDB(),ADDC()和ADDD()。如果線程t1訪問方法addB(),是否可以同時線程t2訪問addC()方法?如果不是t2會是什麼狀態?

class Test{ 
     private Integer a; 
     private Integer b; 
     private Integer c; 
     private Integer d; 


    public void addA(){ 
     synchronized(a) { 
     a++; 
     } 
    } 
    public synchronized void addB(){ 
     b++; 
     } 

    public synchronized void addC(){ 
     c++; 
     } 

    public synchronized void addD(){ 
     d++; 
     }  
    } 
+0

整數是不可改變的,它不會改變。當你做一個++時,它實際上會創建一個新的對象a。因此,你的鎖會變得混亂,因爲當a被刪除並且值被分配給新的a時,鎖將會丟失。這並不能真正幫助你解決問題,但可能會解決一個錯誤。你可以使用int而不是Integer。 – Mike 2010-06-23 18:26:30

+0

@Mike - 漂亮。實際上,我認爲在這種特殊情況下,它不會導致錯誤,但如果他在他的'addA'實現中添加了任何代碼,則可能會很好。另外,他不能在'int'上同步,因爲它是一個原語,但他可以使用AtomicInteger。 – danben 2010-06-23 18:28:05

+0

@danben謝謝。我不知道關於不在int上同步。我想我從來沒有嘗試過一種原始。你每天都會學到一些東西。 – Mike 2010-06-23 18:36:42

回答

4

鎖確實一次只允許一個線程,但不同的鎖不會相互影響。

在你的榜樣,你有兩個鎖 - 一個對屬於a互斥體,和一個對屬於this(當您使用​​關鍵字,如您正確地在您的文章中提到這是隱含的)互斥。

因此撥打addB()將被同步,但不會阻止對任何其他方法的調用。如果一個線程持有this上的鎖,另一個線程可以保持鎖a,並且多個其他線程可以同時執行addC()addD()

編輯:順便說一句,你可能有興趣瞭解AtomicInteger類,如果你真的與Integer s工作。它們提供原子操作,使您不必擔心在它們周圍進行同步。

+0

我想那麼我們不應該告訴同步創建對象鎖,因爲其他線程可以在對象鎖狀態下訪問非同步方法。我仍然困惑什麼是對象鎖定? – Tony 2010-06-24 09:58:49

+0

@Thomman:我不確定你的意思是「在對象鎖狀態」。 Java中的每個對象都有自己的互斥體 - 當您在一個對象上同步時,這個互斥體需要在線程進入同步塊之前進行。 – danben 2010-06-24 12:49:25

1

您的代碼中有兩個鎖,只有一個Thread將能夠遍歷Lock#1或Lock#2。兩個鎖都是獨立的,這意味着它們不會排斥彼此的線程。

鎖#1同步對一個對象

public void addA(){ 
     synchronized(a) { 
     a++; 
     } 
    } 

鎖#2同步的測試實例(本)

public synchronized void addB(){ 
     b++; 
     } 

ADDC()和ADDD()必須在對他們沒有鎖所有,任何數量的線程都可以同時訪問這些線程。

1

一個同步塊只是一個環境,你可以把它被「執行」的對象視爲reentrant lock。的確,只有一個線程可以同時鎖定在一個對象上。

方法C和D從不鎖定,任何線程都可以隨時執行。

和其他指出的一樣,當您執行a++時,您將創建一個新的Integer實例。

0

鎖提供了一個同步線程的機制。這意味着在同一時間點,只有一個線程可以訪問對象的AddB方法。 除非在完成代碼後釋放鎖,否則下一代碼迭代不能進入該塊。

0

鎖定螺紋的依賴於對象的實例中使用 例如:

class MyClass extends Thread{ 
    Test instanceObj=null;  
    public MyClass(Test obj){ 
     instanceObj=obj; 
    } 

    public void run(){ 
     obj.addB(); 
    } 
} 

的ADDB()函數可以rewriten作爲

public void addB(){ 
    synchronized(this){ 
    //func 
} 
} 
  • 這裏鎖是在對象上用於訪問該函數的片段。其他功能可以被其他線程訪問。
  • 對addA上的鎖定的更多信息在obj.a上,該對象具有自己的獨立鎖。因此,兩個不同的線程可以同時訪問addA和addB。