1

我尝试使用 Java 剪辑对象播放信号。我开始剪辑,然后等待 STOP 事件被触发,直到我继续线程。我观察到,如果我退出调用线程,这可能发生在我的应用程序中,声音不会播放或只播放第一部分。

这在大多数情况下都可以正常工作,但是,大约每 50 次,既不会触发 START 事件,也不会触发 STOP 事件,这会导致当前线程永远等待。

现在的问题是,我是否在同步方面做错了什么,导致我失去了事件?

private static volatile boolean isPlaying = false;
private static final Object waitObject = new Object();

public static void playClip(...)

...

    Clip clip = (Clip) AudioSystem.getLine(...);

    clip.addLineListener(new LineListener() {
        public void update(LineEvent event) {
            if (event.getType() == LineEvent.Type.STOP) {
                event.getLine().close();
                synchronized (waitObject) {
                    isPlaying = false;                        
                    waitObject.notifyAll();
                }
            }
        }
    });


    // start playing clip
    synchronized (waitObject) { 
        isPlaying = true;
    }
    clip.start();

    // keep Thread running otherwise the audio output is stopped when caller thread exits
    try {
        while (isPlaying) {
            synchronized (waitObject) {
                waitObject.wait();                    
            }
        }
    } catch (InterruptedException e) {           
        e.printStackTrace();
    }
}

这是使用的新版本 CountDownLatch

private static volatile CountDownLatch playingFinished = new CountDownLatch(1);

public static void playClip(...)

...
    Clip clip = (Clip) AudioSystem.getLine(...);
    clip.open(audioInputStream);

    // use line listener to take care of synchronous call
    clip.addLineListener(new LineListener() {
        public void update(LineEvent event) {
            if (event.getType() == LineEvent.Type.STOP) {
                event.getLine().close();
                playingFinished.countDown();
            }
        }
    });

    clip.start();

    try {
        playingFinished.await();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    playingFinished = new CountDownLatch(1);


我没有包含调试语句,但它们表明线程挂起,playingFinished.await();因为没有触发 STOP 事件并且playingFinished.countDown();从未调用过。

4

1 回答 1

0

帮自己一个忙,重新编写代码以使用CountDownLatch代替低级等待通知 API。然后,您的问题可能会自行消失。

public void playClip() throws Exception {
  final CountDownLatch playingFinished = new CountDownLatch(1);
  final Clip clip = (Clip) AudioSystem.getLine(...);
  clip.open(...);
  clip.addLineListener(new LineListener() {
    public void update(LineEvent event) {
      if (event.getType() == LineEvent.Type.STOP) {
        event.getLine().close();
        playingFinished.countDown();
      }
    }
  });
  clip.start();
  try {
    playingFinished.await();
  } catch (InterruptedException e) {
    Thread.currentThread().interrupt();
  }
}
于 2012-04-24T08:57:36.910 回答