2015-04-01 31 views
1

我正在通過this教程。我瞭解volatile關鍵字的用法。但是,當我試圖達到相同的結果,而不使用volatile關鍵字與同步塊中的關注變量的操作,它不起作用。它引發IllegalMonitorStateException。這是我試過的修改過的代碼。用同步塊替換volatile不起作用

public class VolatileTest { 
private static Integer MY_INT = 0; 

public static void main(String[] args) { 
    new ChangeListener().start(); 
    new ChangeMaker().start(); 
} 

static class ChangeListener extends Thread { 
    @Override 
    public void run() { 
     synchronized(MY_INT){ 
     int local_value = MY_INT; 
     while (local_value < 5){ 
      if(local_value!= MY_INT){ 
       System.out.format("Got Change for MY_INT : {0}", MY_INT); 
       local_value= MY_INT; 
        try { 
       MY_INT.wait(); 
      } catch (Exception e) { e.printStackTrace(); }} 
      } 
     } 
    } 
} 

static class ChangeMaker extends Thread{ 
    @Override 
    public void run() { 
     synchronized(MY_INT){ 
     int local_value = MY_INT; 
     while (MY_INT <5){ 
      System.out.format("Incrementing MY_INT to {0}", local_value+1); 
      MY_INT = ++local_value; 
      try { 
       MY_INT.notify(); 
      } catch (Exception e) { e.printStackTrace(); } 
     } 
    } 
}}} 

我想知道的是,在這種情況下是揮發性的替換用synchronized塊,如果是,那麼該怎麼辦呢? 謝謝。

+0

請提供異常堆棧跟蹤。 – GhostCat 2015-04-01 07:58:18

回答

6

的問題是在這裏:

MY_INT = ++local_value; 

MY_INTInteger變量,當您分配一個新的價值給它的對象,你是鎖在這裏:

synchronized(MY_INT){ 

會有所不同您要在此通知的對象:

MY_INT.notify(); 

。 ..這將導致例外。


解決辦法是使鎖對象static final。顯然,這意味着你不能指定它......但這是整個重點!

+0

好的答案,除了Integer對象的不變性不是問題。任何時候你都有一個變量'Foo foo;',並且你賦值給'foo = ...;',它會更新對象引用。無論Foo類是否是不可改變的都沒關係。 – 2015-04-01 12:55:35

+0

@jameslarge - 我知道Integer不變性不是問題... – 2015-04-01 13:30:28

+0

是的,但是noob很容易誤解你說的話:「整數對象是不可移動的,當你賦值給一個Integer變量時......」。這是兩個獨立的子句,但是當你將它們放在同一段落中時,某個不熟悉該語言的人可能會記得它,就像你說過的那樣,_ because_ Integer對象是不可變的。 – 2015-04-01 13:52:35