2

我想了解java中的同步塊的概念。 截至我已閱讀的文檔中,我明白如果我們獲取 鎖(使用實例變量的同步塊),那麼我們 無法獲取該類中同一對象的同步鎖。但 當我嘗試使用以下代碼片段時,發現我的 理解出錯了。JAVA同步對象在不同的​​方法

即,我可以同時在兩個不同的 方法中獲取鎖 (同一個實例變量上的同步塊)。當線程啓動時,它將運行 方法並無限期地等待並且不會從同步的 塊中跑出。同時,如果我使用相同的 線程調用停止方法,它將進入同步塊並執行通知 語句。我在Java文檔搜索,但我找不到任何。

這是代碼片段:

public class MyClass extends Thread 
{ 
    private Object lock = new Object(); 
    public void run() 
    { 
     synchronized(lock) 
     { 
      lock.wait() 
     } 
     //other code 
    } 
    public void stop() 
    { 
     synchronized(lock) 
     { 
      lock.notify() 
     } 
     //other code 
    } 
} 

這裏的代碼片段我有多管理MyClass的螺紋:

public class MyClassAdmin 
{ 
    MyClass _myclass; 
    public MyClassAdmin() 
    { 
     _myclass=new MyClass(); 
     _myclass.start(); 
    } 
    public void stop() 
    { 
    _myclass.stop(); 
    } 
    public static void main(String args[]) 
    { 
    MyClassAdmin _myclassAdmin=new MyClassAdmin(); 
    _myclassAdmin.stop(); 
    } 
} 

根據我的理解,當線程啓動,將收購鎖定「鎖定」對象(MyClass的run方法中的同步塊)。當我調用停止方法時,它應該無限期地等待,直到run方法從synchronized塊中出來(在這種情況下永遠不會發生)。但是當我執行時,調用stop方法獲取鎖'對象'並通知導致線程關閉的對象。

+0

你可以請你分享你的代碼如何創建線程? – Lathy

+0

這是不是多線程..你的程序是一個單線程與主線程運行後面 – Lathy

回答

1

你的兩個方法都使用相同的鎖。如果MyClass線程恰好在主線程調用stop方法之前開始等待,則stop方法仍然可以繼續,因爲等待線程會釋放該鎖。一旦一個線程進入等待方法,它會在它進入休眠狀態之前釋放該鎖,並且在它退出等待方法之前不會重新獲取該鎖。

這是相關的API doc for Object#wait,第二段涵蓋了我上面介紹的關於如何等待解鎖的內容。注意它說你必須在一個循環中調用這個方法的部分,否則你有一個訂單相關性錯誤,當另一個線程可以開始等待之前,通知到達主線程時可能導致等待線程掛起。

公共最終空隙等待() 拋出InterruptedException的

造成當前線程等待,直到其他線程調用 notify()方法或此對象的notifyAll的()方法。在其他 單詞中,此方法的行爲與其僅執行呼叫 wait(0)完全相同。

當前線程必須擁有該對象的監視器。該線程發佈 該監視器的所有權,並等待另一個線程通知 等待此對象監視器的線程通過調用notify方法或notifyAll方法的 喚醒。然後線程 等待,直到它可以重新獲得顯示器的所有權並恢復執行 。

如在一個參數的版本,中斷和雜散喚醒是 可能的,並且這種方法應該總是在一個循環中使用:

synchronized (obj) { 
    while (<condition does not hold>) 
     obj.wait(); 
    ... // Perform action appropriate to condition 
} 

此方法應該僅由一個線程是所有者被稱爲 此對象的監視器。有關 線程可以成爲監視器所有者的說明,請參閱notify方法。

瞭解這是一個玩具的例子,但子類的線程和重寫線程方法是混淆。使用Runnable而不是Thread的原因之一是不會因錯誤地覆蓋Thread方法而導致問題。

+0

我對synchronized塊的懷疑被清除了。感謝您的解釋@Nathan Hughes – Rock

+0

@Rock請記住注意,並在滿意答案時將答案標記爲正確。真正的精神:) –

-2

這是多線程的,它可能永遠等不到。 在你的情況你很幸運,_myclassAdmin.stop();在MyClass開始執行並執行wait()後執行;

我在將方法stop()名稱更改爲stop1()之後運行程序,它正在永久等待。

要獲得一致的行爲做一兩件事,在主像放了1秒睡兩個方法調用之間:現在

MyClassAdmin _myclassAdmin=new MyClassAdmin(); 
Thread.sleep(1) 
_myclassAdmin.stop(); 

,執行將始終停止。另外,當一個線程調用wait()時,它釋放與之關聯的監視器,因此任何其他線程都可以獲得該鎖併發出notify()/ notifyAll()以喚醒等待的線程。這是期望

+1

Downvoted爲不好的建議添加睡眠方法。處理這個問題的正確方法是使用帶有條件變量的循環,如文檔中所述。 –