线路监听器事件丢失

问题描述:

我尝试使用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();挂起,因为停止事件没有被解雇,并永远不会调用playingFinished.countDown();

帮你自己一个忙,并重写代码,以使用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(); 
    } 
} 
+0

我使用CoundDownLatch构造而不是wait/notify,但问题仍然存在。我想到它似乎取决于JVM。当我使用OpenJDK时,事件有时会丢失,当我使用Java Standard Edition时,问题不会发生。 – Thomas789 2012-04-24 09:50:17

+0

请发布更改后的代码。如果它依赖于jvm,那么它就是99%,因为你做错了一些事情,只要它运行起来就很幸运。 – 2012-04-24 09:58:10

+0

我编辑了这个问题并发布了更改后的代码,现在包含'CoundDownLatch'而不是'wait/notify' – Thomas789 2012-04-24 10:38:18