2015-06-11 64 views
0

在我開始使用條件變量之前,我試圖理解對象的等待原則。我編寫了一些代碼來了解更多內容,但不能按預期工作。java.lang.IllegalMonitorStateException雖然從同步塊調用等待

應該發生的事情是Waiter類在線程啓動時等待。 同時,通告程序類使用循環將一些元素添加到列表中。一旦通知已經這樣做了就會通知服務員應該簡單地打印,它已被通知,但我得到illegalmonitorstate例外

這是我的輸出

Exception in thread "Waiter Thread" java.lang.IllegalMonitorStateException 
at java.lang.Object.wait(Native Method) 
at tutorials.waitnotify.Waiter.run(Waiter.java:26) 
at java.lang.Thread.run(Thread.java:745) 
0 [Waiter Thread] DEBUG tutorials.waitnotify.Waiter - Starting waiter.... 
2002 [Notifier Thread] DEBUG tutorials.waitnotify.Waiter - Starting  
notifier... 
3005 [Notifier Thread] DEBUG tutorials.waitnotify.Waiter - Element added [1] 
4007 [Notifier Thread] DEBUG tutorials.waitnotify.Waiter - Element added [2] 
5012 [Notifier Thread] DEBUG tutorials.waitnotify.Waiter - Element added [3] 
Exception in thread "Notifier Thread" java.lang.IllegalMonitorStateException 
7022 [Notifier Thread] DEBUG tutorials.waitnotify.Waiter - Object about to  
notify 
at java.lang.Object.notify(Native Method) 
at tutorials.waitnotify.Notifier.run(Notifier.java:42) 
at java.lang.Thread.run(Thread.java:745) 

這是代碼 正如你可以看到我m試圖在一個普通的鎖定對象上進行同步。

public class Notifier implements Runnable { 

private static final Logger LOGGER = LoggerFactory.getLogger(Waiter.class); 
private List<Integer> list; 
private Object commonLock; 

public Notifier(Object lock) { 
    this.list = new ArrayList<>(); 
    this.commonLock = lock; 
} 

public void run() { 
    LOGGER.debug("Starting notifier...."); 
    synchronized (commonLock) { 
     for (int i = 1; i <= 3; i++) { 
      try { 
       Thread.sleep(1000); 
      } catch (InterruptedException ie) { 
       LOGGER.debug("Interrupted"); 
      } 
      list.add(i); 
      LOGGER.debug("Element added [{}]", i); 
     } 
     LOGGER.debug("About to notify"); 
     notify(); 
    } 
} 
} 

public class Waiter implements Runnable { 

private static final Logger LOGGER = LoggerFactory.getLogger(Waiter.class); 
private final Object commonLock; 

public Waiter(Object lock) { 
    this.commonLock = lock; 
} 

public void run() { 
    LOGGER.debug("Starting waiter...."); 
    synchronized (commonLock) { 
     try { 
      wait(10000); 
     } catch (InterruptedException ie) { 
      LOGGER.debug("Interrupted"); 
     } 
    } 
    LOGGER.debug("Object been notified"); 
} 
} 

public class WaiterNotifierMain { 

public static void main(String[] args) { 
    BasicConfigurator.configure(); 

    Object lock = new Object(); 
    Waiter waiter = new Waiter(lock); 
    Notifier notifier = new Notifier(lock); 

    Thread waiterThread = new Thread(waiter); 
    Thread notifierThread = new Thread(notifier); 

    notifierThread.setName("Notifier Thread"); 
    waiterThread.setName("Waiter Thread"); 
    waiterThread.start(); 
    try { 
     Thread.sleep(2000); 
    } catch (InterruptedException e) { 
     e.printStackTrace(); 
    } 
    notifierThread.start(); 
} 
} 

任何指針,將不勝感激。在此先感謝

回答

2

你應該做

  • commonLock .wait(10000)
  • commonLock .notify()

,因爲你在等你得到一個例外,通知「這個」。而且你沒有在「這個」上同步。

(),您可以考慮使用notifyAll的,而不是notify()方法:

如果您計劃擁有多個服務員線程,記住通知()將只喚醒一個服務員線程在同一時間。如果您想一次喚醒所有服務器線程,則應該使用notifyAll()方法。

即使知道永遠不會有多個Waiter線程,我認爲最好使用notifyAll()而不是notify(),因爲通告程序對象不知道有多少線程正在偵聽對象...

+0

「最好使用notifyAll()而不是notify()。」這是一個非常全面的聲明,在答案中沒有任何理由...... –

+0

乾杯@Stefan工作。我只使用通知,因爲我有一個線程正在等待。 –

+0

@你是對的......如果你只有一個線程在等待通知,notify()也可以工作。如果您有多個Waiters,只有一個會收到通知。如果這是所需的行爲,那就沒問題。如果沒關係(因爲你知道,你只有一個Waiter線程),我仍然認爲使用notifyAll()是最好的做法,因爲Waiter對象不知道有多少對象正在等待鎖目的。通過使用notifyAll(),無論是否有其他人在等待鎖定,您都確定該通知是由服務員獲得的。 –