2017-07-06 106 views
0

由於這是我的第一篇文章,我很抱歉任何錯誤的結構。我正在開發一個個人項目,這是一個用java製作的時鐘,用於顯示時間/日期/時間,每個季度播放一個音頻文件以及每小時鐘聲。 GUI是用擺動項目構建的。等待()和通知()與linelistener

當時鍾達到一定時間時,它必須發出聲音/播放聲音,我希望在時鐘發出聲音時在GUI上顯示圖標。此刻,該圖標在方法開始時切換並在結束時再次切換。我想方法等待()而音頻正在播放之前,第二次切換圖標。 (也許有更好的方法來做到這一點。)

我初出茅廬用java我覺得如果我使用的wait()通知()不正確。我已經看過例子,直到我的腦袋旋轉,我仍然不確定我需要的解決方案。

我使用LineListener以通知剪輯播放完畢,並可以進行切換的圖標。

這是打風鈴方法:

public void play() throws InterruptedException { 
    while (mute == false) { 
     synchronized (chimeLock) { 
      ChimeClockGUI.toggleChimeIcon(); 
      clip.start(); 
      do { 
       chimeLock.wait(); 
      } while (clip.isActive()); 
      ChimeClockGUI.toggleChimeIcon(); 
     } 
    } 
} 

而且

public void toll() throws InterruptedException { 
    if (mute == false) { 
     synchronized (chimeLock) { 
      ChimeClockGUI.toggleChimeIcon(); 
      ONTHEHOUR.clip.start(); 
      do { 
       chimeLock.wait(); 
      } while (ONTHEHOUR.clip.isActive()); 
      if (Calendar.getInstance().get(Calendar.HOUR) == 0) { 
       clip.loop(11); 
       do { 
        chimeLock.wait(); 
       } while (clip.isActive()); 
      } else if (Calendar.getInstance().get(Calendar.HOUR) == 1) { 
       clip.start(); 
       do { 
        chimeLock.wait(); 
       } while (clip.isActive()); 
      } else { 
       clip.loop(Calendar.getInstance().get(Calendar.HOUR) - 1); 
       do { 
        chimeLock.wait(); 
       } while (clip.isActive()); 
      } 
      ChimeClockGUI.toggleChimeIcon(); 
     } 
    } 
} 

最後,更新()LineListener方法:

@Override 
public void update(LineEvent le) { 
    synchronized (chimeLock) { 
     LineEvent.Type type = le.getType(); 
     if (type == LineEvent.Type.OPEN) { 
      System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") 
        .format(new Timestamp(System.currentTimeMillis())) + ": Clip opened..."); 
     } else if (type == LineEvent.Type.CLOSE) { 
      System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") 
        .format(new Timestamp(System.currentTimeMillis())) + ": Clip closed..."); 
      chimeLock.notifyAll(); 
     } else if (type == LineEvent.Type.START) { 
      System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") 
        .format(new Timestamp(System.currentTimeMillis())) + ": Clip started..."); 
     } else if (type == LineEvent.Type.STOP) { 
      System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") 
        .format(new Timestamp(System.currentTimeMillis())) + ": Clip stopped..."); 
      chimeLock.notifyAll(); 
     } 
    } 
} 

我包括請撥打播放的方法()收費()

chimeService.scheduleAtFixedRate(() -> { 
    try { 
     ChimeClockSound.TOLL.toll(); 
     } catch (InterruptedException ex) { 
      Logger.getLogger(ChimeClockGUI.class.getName()) 
        .log(Level.SEVERE, null, ex); 
    } 

任何幫助或建議將不勝感激。謝謝!

+0

注意'synchronized'函數阻止當前(this)對象,並且沒有任何其他線程可以訪問它。如果對象/類與你的GUI相關,不建議鎖定'this',只需要一個'object'。 – 2017-07-06 20:26:47

+0

在這種情況下'play()'和'toll()'只能從一個'ScheduledExecutor'線程調用。 – cbs6f

回答

0

這裏的第一個問題是,clip.isRunning()回報false,直到數據實際開始加載,所以你應該確保wait()總是調用一個do-while循環:

do { 
    wait(); 
} while (clip.isRunning()); 

這也是更好地叫wait/notify上的專用鎖對象而不是整個類的實例。這樣,wait/notify的其他用途不會干擾,您的方法不需要​​,這可能會減慢速度。

private final Object chimeLock = new Object(); 

有了這個,你可以替換wait()有:

synchronized (chimeLock) { 
    chimeLock.wait(); 
} 

...並將其替換notifyAll()

synchronized (chimeLock) { 
    chimeLock.notifyAll(); 
} 

...並移除方法聲明​​,因爲它現在正在鎖定對象上進行同步。

最後要記住的是InterruptedException只有在線程被中斷時纔會拋出,這通常意味着某些東西(如JVM)希望線程停止運行。當你抓住這個時候,你應該包裝起來並儘快返回。

+0

謝謝你在這方面的幫助。我已經實現了你的建議,但是在調用chimeLock.notifyAll()時似乎沒有任何事情發生。 – cbs6f

+0

您是否從方法中移除了'synchronized'?你的代碼現在是什麼樣的?另外,我剛剛注意到,如果剪輯從未在開關塊中啓動,則需要確保「toll」不進入do-while循環,因爲「update」永遠不會被調用。 –

+0

我已更新我的問題以反映更改。理論上,當收費被稱爲一個剪輯應該始終播放。另外,我添加了調用'play()'和'toll()'的方法,以防萬一我在那裏做錯了什麼。 – cbs6f