2014-02-07 100 views
0

我有3個類,如下所示。我已經使用synchronized(b)這樣,一個對象獲取B對象上的鎖,並且在A中的foo方法完成工作之前,將不會調用b中的任何方法。Java多線程同步(對象)

但是,這似乎不起作用(見最後的輸出)。事實上,racethread能夠調用對象b上的方法。

注意:您可以創建一個簡單的java項目,並將下面的代碼添加到一個文件中以嘗試並執行。

package com.threads.main.deadlock;

class A { 
    void foo(B b) { 
     synchronized (b) { // Trying to get lock on b here 
      String name = Thread.currentThread().getName(); 
      System.out.println(name + " entered A.foo"); 
      try { 
       Thread.sleep(1000); 
      } catch (Exception e) { 
       System.out.println("A Interrupted"); 
      } 
      System.out.println(name + " trying to call B.last()"); 
      b.last(); 
     } 
    } 

    synchronized void last() { 
     System.out.println("Inside A.last"); 
    } 
} 
class B { 
    void bar(A a) { 
     synchronized (a) { 

      String name = Thread.currentThread().getName(); 
      System.out.println(name + " entered B.bar"); 
      try { 
       Thread.sleep(1000); 
      } catch (Exception e) { 
       System.out.println("B Interrupted"); 
      } 
      System.out.println(name + " trying to call A.last()"); 
      a.last(); 
     } 
    } 

    synchronized void last() { 
     System.out.println("Inside B.last"); 
    } 
} 
public class Deadlock implements Runnable { 
    A a = new A(); 
    B b = new B(); 

    Deadlock() { 
     Thread.currentThread().setName("MainThread"); 
     Thread t = new Thread(this, "RacingThread"); 
     t.start(); 

     new Thread(new Dum(a)).start(); 
     a.foo(b); // get lock on a in this thread. 
     System.out.println("Back in main thread"); 
    } 

    public void run() { 
     b.bar(a); // get lock on b in other thread. 
     System.out.println("Back in other thread"); 
    } 

    public static void main(String args[]) { 
     new Deadlock(); 
    } 
} 

class Dum implements Runnable { 

    A a = null; 

    public Dum(A a) { 
     this.a = a; 
    } 

    @Override 
    public void run() { 
     int i =0; 
     while (i++ < 5) { 
      System.out.println("Trying a.last .. dum"); 
      a.last(); 
     } 
    } 

} 

輸出:

RacingThread entered B.bar 
Trying a.last .. dum 
MainThread entered A.foo 
RacingThread trying to call A.last() 
MainThread trying to call B.last() 
Inside B.last 
Inside A.last 
Back in other thread 
Back in main thread 
Inside A.last 
Trying a.last .. dum 
Inside A.last 
Trying a.last .. dum 
Inside A.last 
Trying a.last .. dum 
Inside A.last 
Trying a.last .. dum 
Inside A.last 
+0

真的不清楚你在這裏期待什麼;沒有什麼會導致僵局。 –

+2

可能是另一種誤解2線程需要在同一個對象監視器上進行同步的情況,並且沒有辦法「鎖定對象」。 – Kayaman

+0

@Kayaman,你可否請求詳細說明'2個線程需要在同一個對象監視器上同步',你可以修改這個類並顯示它。很難理解,因爲我是多線程新手。另外,當我添加同步(對象)對象時,下一點將被剛剛進入對象監視器的線程鎖定;並且在線程釋放監視器之前,鎖定對象內的任何方法都不會被其他線程訪問? – Zeus

回答

0

你的A和B線程使用不同的對象在他們的方法同步。

所以你的假設

一個對象獲取B對象上的鎖,沒有在B 的方法將被調用,直到在一個Foo方法完成掃尾工作。

是錯誤的。 A.foo運行時,它使用B的實例進行同步。但是,這隻能阻止B.last的並行運行,因爲B.foo在A上有一個同步塊。但是當然,當A.foo嘗試調用b.last時,它不會導致任何阻塞,因爲A.foo已經在b的監視器內。

如果你有這樣的方法:

synchronized void last() { 
} 

這是basicly等同於:

void last() { 
    synchronized(this){ //so in case of Class B it means: this = the B instance 
    } 
} 

我建議名稱的所有線程,並添加Thread.currentThread()的getName。 ()到每一個單一的系統,你會更好地理解它。