wait()和notify()与linelistener

时间:2017-07-06 20:05:19

标签: java

由于这是我的第一篇文章,我为其结构的任何错误道歉。我正在开发一个个人项目,这是一个用java制作的时钟,用于显示时间/日期/日期,每季度播放一个音频文件以及一小时钟声。 GUI使用swing项目构建。

当时钟到达时,它必须响铃/播放声音,我希望在时钟响起的同时在GUI上显示一个图标。此时,图标在方法开头切换,并在结束时再次切换。我希望在播放音频的同时 wait()的方法在第二次切换图标之前。 (也许有更好的方法来做到这一点。)

我对java缺乏经验,感觉好像我正在使用 wait() notify()。我看了一些例子,直到我的头旋转,我仍然不确定我需要的解决方案。

我正在使用 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 update()方法:

@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();
        }
    }
}

我包括调用 play() toll()的方法。

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

非常感谢任何帮助或建议。谢谢!

1 个答案:

答案 0 :(得分:0)

这里的第一个问题是clip.isRunning()返回false直到数据实际开始加载,因此您应该确保始终使用do-while循环调用wait()

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

最好在专用锁对象上调用wait / notify,而不是在类的整个实例上调用。这样,wait / notify的其他用途不会干扰,您的方法也不一定是synchronized,这可能会减慢速度。

private final Object chimeLock = new Object();

使用此功能,您可以将wait()替换为:

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

...并将notifyAll()替换为:

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

...并从方法声明中删除synchronized,因为它现在正在锁定对象上进行同步。

要记住的最后一件事是InterruptedException仅在线程被中断时抛出,这通常意味着某些东西(如JVM)希望线程停止运行。当你抓住这个时,你应该把事情包起来并尽快返回。