2013-02-25 32 views
3

我想在另一個同步語句中運行一個方法。兩個同步語句。他們如何工作?

MyClass的

public class MyClass { 

    private Object lockObject = new Object(); 

    public void testFirst() { 
     synchronized (lockObject) { 
      System.out.println("Entered testFirst() sync"); 
      testSecond(); 
      System.out.println("Leaving testFirst() sync"); 
     } 
    } 

    private void testSecond() { 
     synchronized (lockObject) { 
      System.out.println("Entered testSecond() sync"); 
     } 
    } 

} 

package com.replanet; 

public class Main { 

    public static void main(String[] args) { 

     MyClass myClass = new MyClass(); 
     myClass.testFirst(); 
    } 

} 

輸出

Entered testFirst() sync 
Entered testSecond() sync 
Leaving testFirst() sync 

我預期另一個輸出。

Entered testFirst() sync 
Leaving testFirst() sync 
Entered testSecond() sync 

爲什麼不會testSecond()等到testFirst()完成它的工作嗎?

+0

+1供ICP參考。 – L0j1k 2013-02-25 11:26:04

+0

你很自然地不理解鎖。 請閱讀:http://docs.oracle.com/javase/tutorial/essential/concurrency/ – fredcrs 2013-02-25 11:34:20

+0

@fredcrs,謝謝。我會閱讀文檔。我正在閱讀Fred Long撰寫的名爲「Java併發指南」的書。 – 2013-02-25 13:22:36

回答

4

你會看到這個看似奇怪的行爲,因爲每個鎖都與請求它的線程相關聯,一旦你鎖定了鎖定,直到你解鎖。

在您的代碼中,您將獲得兩次相同的鎖定,因此第二次嘗試將立即成功,因爲您已經擁有它。

參考文獻見here

當一個線程正在執行同步方法爲對象,即調用針對同一對象塊(暫停執行)同步方法所有其他線程直到第一線程是用物體完成。

+0

只需添加:如果它不能以這種方式工作,則此方法將自己鎖死 – jontro 2013-02-25 11:32:44

+0

@OldCurmudgeon,「每個鎖都與請求的線程關聯」。不是用線程而是用對象,不是嗎? – 2013-02-25 11:36:04

+0

@RedPlanet - 很確定它是''Thread',它擁有'Object'上的鎖。也許我誤解了你/它。 – OldCurmudgeon 2013-02-25 11:40:39

3

由於進入第一​​部分,你必須有對象lockObject的鎖,當你在第二​​節中,你仍然有它,所以它繼續到達。當運行testFirst時,​​塊中的testSecond沒有任何變化。

1

Beause testSecond()testFirst()

控制流動酷似以下相關: -

System.out.println("Entered testFirst() sync"); 
     System.out.println("Entered testSecond() sync"); 
System.out.println("Leaving testFirst() sync"); 
1

同步是圍繞被稱爲內部鎖或監視器內部實體建鎖。
每個對象都有一個與之相關的固有鎖。按照慣例,需要獨佔且一致地訪問對象字段的線程在訪問對象之前必須先獲取對象的內部鎖,然後在完成內部鎖時釋放內部鎖。據說一個線程擁有它獲取鎖定和釋放鎖定之間的固有鎖定。只要線程擁有內部鎖,其他線程就不會獲得相同的鎖。另一個線程在嘗試獲取鎖時會阻塞。

所以你的線程是lockObject的所有者,因此它可以與lockObject輸入所有代碼塊中

2

有幾件事情要記住:

  • ​​塊重入:當你持有鎖通過​​聲明,您使用相同的顯示器可以進入另一個​​塊 - 在你的情況下,沒有什麼能阻止你從哪打來testSecondtestFirst
  • 現在想象一下,2種方法ü SED顯示器不同,你仍然會得到相同的輸出,因爲沒有其他線程將舉行的testSecond
  • 鎖IF 2種方法使用了兩種不同的鎖另一個線程保持在testSecondtestFirst的執行中使用的鎖將不會跳過呼叫testSecond並繼續前進,它會阻止,直到鎖再次可用
0

我編輯了我發佈的代碼。同步的陳述是有意義的,不是嗎?

MyClass的

public class MyClass { 

    private Object lockObject = new Object(); 

    public void testFirst() throws InterruptedException { 
     // Here is something that should not be synchronized 
     synchronized (lockObject) { 
      System.out.println("testFirst() is about to fall asleep. " 
        + Thread.currentThread().getName()); 
      Thread.sleep(2000); 
      System.out.println("testFirst() woke up. " + Thread.currentThread().getName()); 
     } 
    } 

} 

MyThread的

public class MyThread extends Thread { 

    private MyClass myClass; 

    public MyThread(MyClass myClass) { 
     this.myClass = myClass; 
    } 

    @Override 
    public void run() { 
     try { 
      myClass.testFirst(); 
     } catch (InterruptedException e) { 
      interrupt(); 
     } 
     super.run(); 
    } 

} 

用法

package com.replanet; 

public class Main { 

    public static void main(String[] args) { 
     MyClass myClass = new MyClass(); 
     MyThread mThread = new MyThread(myClass); 
     MyThread anotherThread = new MyThread(myClass); 
     mThread.start(); 
     anotherThread.start(); 
    } 

} 

輸出

testFirst() is about to fall asleep. Thread-0 
testFirst() woke up. Thread-0 
testFirst() is about to fall asleep. Thread-1 
testFirst() woke up. Thread-1