2015-09-24 36 views
2

我試圖使用兩個線程打印一個同步的Integer對象(mInt)直到10.但是其中一個線程鎖定另一個線程會拋出下面粘貼的異常。有人可以在這裏指出我的錯誤。這是更多的Java相關的問題,但包括「android」標籤,因爲我已經爲android編碼它,我需要嘗試在它的某個時間。嘗試從共享資源打印偶數和奇數

09-24 15:24:17.198 10621-11400/com.sameer.android.samplecode E/AndroidRuntime:致命異常:線程364 工藝:com.sameer.android.samplecode,PID:10621 java.lang.IllegalMonitorStateException:通過notify()之前的線程鎖定對象() at java.lang.Object.notify(Native Method) at com.sameer.android.samplecode.MainActivity $ Even.run(MainActivity.java:55 )

public class MainActivity extends AppCompatActivity { 
    private Integer mInt; 

    class Odd extends Thread { 
     private final String TAG = Odd.class.getSimpleName(); 

     @Override 
     public void run() { 
      Log.i(TAG, "Odd() Started...."); 
      synchronized (mInt) { 
       try { 
        while (mInt <= 10) 
        { 
         while (mInt % 2 != 1) { 
          Log.i(TAG, "Odd... Looping " + mInt); 
          mInt.wait(); 
         } 
         mInt++; 
         Log.i(TAG, "Odd " + mInt); 
         mInt.notify(); 
        } 
       } 
       catch (InterruptedException e) { 
        Log.e(TAG, "Odd() " + e.getMessage()); 
       } 
      } 
      Log.i(TAG, "Odd() Ended...."); 
     } 
    } 

    class Even extends Thread { 
     private final String TAG = Even.class.getSimpleName(); 

     @Override 
     public void run() { 
      Log.i(TAG, "Even() Started...."); 
      synchronized (mInt) { 
       try { 
        while (mInt <= 10) 
        { 
         while (mInt % 2 != 0) { 
          Log.i(TAG, "Even... Looping " + mInt); 
          mInt.wait(); 
         } 
         mInt++; 
         Log.i(TAG, "Even " + mInt); 
         mInt.notify(); 
        } 
       } 
       catch (InterruptedException e) { 
        Log.e(TAG, "Even() " + e.getMessage()); 
       } 
      } 
      Log.i(TAG, "Even() Ended...."); 
     } 
    } 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     mInt = new Integer(0); 
     Button button = (Button) findViewById(R.id.button); 
     button.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       Even even = new Even(); 
       even.start(); 

       Odd odd = new Odd(); 
       odd.start(); 
      } 
     }); 
    } 
} 

回答

1

當你增加mInt,你做不修改當前Integer對象,但創建一個新的 Integer對象。因此,對新的(未鎖定的)對象執行對notify的呼叫。由於必須在鎖定的對象上調用notify,因此發生了IllegalMonitorStateException

其他方備註(不是答案的一部分):

您的代碼有一個根本性的問題。您在run方法的開始處鎖定mInt。因此,只有一個線程可以輸入其​​塊。第二個線程將等待mInt上的鎖定,直到第一個線程離開​​塊,即終止。因此,最終會出現死鎖,因爲第一個線程只會增加一個時間,並在其​​塊內等待其他線程執行下一個增量。但是,第二個線程無法執行此操作,因爲它無法輸入自己的​​塊(直到第一個線程釋放鎖mInt)。

+0

嘿馬蒂亞斯,你的第一段與我有關。感謝您的評論。 – Sameer

+1

我覺得你也應該編輯第二段。我可能誤導別人。 – Sameer

0

感謝Matthias!你的迴應(部分)幫助我解決了我懷疑的問題,並且你已經確定了它。問題在於mInt被重新創建,因此失去了參考。我通過創建類似於Integer的類來解決該問題。我粘貼了下面的代碼。

import android.os.Bundle; 
import android.support.v7.app.AppCompatActivity; 
import android.util.Log; 
import android.view.View; 
import android.widget.Button; 

public class MainActivity extends AppCompatActivity { 
    private Value mInt; 

    class Odd extends Thread { 
     private final String TAG = Odd.class.getSimpleName(); 

     @Override 
     public void run() { 
      Log.i(TAG, "Odd() Started...."); 
      synchronized (mInt) { 
       try { 
        while (mInt.get() < 10) 
        { 
         while (mInt.get() % 2 != 1) { 
          mInt.wait(); 
         } 
         Log.i(TAG, "Odd " + mInt.get()); 
         mInt.inc(); 
         mInt.notify(); 
        } 
       } 
       catch (InterruptedException e) { 
        Log.e(TAG, "Odd() " + e.getMessage()); 
       } 
      } 
      Log.i(TAG, "Odd() Ended...."); 
     } 
    } 

    class Even extends Thread { 
     private final String TAG = Even.class.getSimpleName(); 

     @Override 
     public void run() { 
      Log.i(TAG, "Even() Started...."); 
      synchronized (mInt) { 
       try { 
        while (mInt.get() < 10) 
        { 
         while (mInt.get() % 2 != 0) { 
          mInt.wait(); 
         } 
         Log.i(TAG, "Even " + mInt.get()); 
         mInt.inc(); 
         mInt.notify(); 
        } 
       } 
       catch (InterruptedException e) { 
        Log.e(TAG, "Even() " + e.getMessage()); 
       } 
      } 
      Log.i(TAG, "Even() Ended...."); 
     } 
    } 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     mInt = new Value(); 
     Button button = (Button) findViewById(R.id.button); 
     button.setOnClickListener(new View.OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       mInt.set(); 
       Even even = new Even(); 
       even.start(); 

       Odd odd = new Odd(); 
       odd.start(); 
      } 
     }); 
    } 
} 

class Value { 
    private int member; 

    public Value() { 
     member = 0; 
    } 

    public int get() { 
     return member; 
    } 

    public void inc() { 
     this.member++; 
    } 

    public void set() { 
     this.member = 0; 
    } 

    public void dec() { 
     this.member--; 
    } 
}