2017-07-06 103 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