如何一次多次停止播放mp3文件?

时间:2013-05-17 18:23:02

标签: java multithreading mp3

我正在尝试按下按钮或从列表中选择播放mp3文件(我已成功管理)。但是,我似乎无法在同一个按钮上多次停止播放该歌曲。

我想做的是在新主题中播放歌曲,再次禁用播放歌曲,直到主题关闭,然后再允许播放。

我的代码如下:

public class SoundFactory {

private Player player;
private static boolean running = false;

private String getFile(String name) {
    String f = "sound" + File.separator + name + ".mp3";
    return f;
}

public void playMP3(String name) {


    if (!running) {
        running = true;

        try {
            FileInputStream fis = new FileInputStream(getFile(name));
            BufferedInputStream bis = new BufferedInputStream(fis);
            player = new Player(bis);
        } catch (Exception e) {
            System.out.println("Problem playing file " + name);
            System.out.println(e);
        }

        // run in new thread to play in background
        new Thread() {
            public void run() {
                try {
                    player.play();
                } catch (Exception e) {
                    System.out.println(e);
                }
            }
        }.start();
        //running = false;
    }
}


public void close() {
    if (player != null) player.close();
}

}

该文件通过以下方式播放:

    SoundFactory sf = new SoundFactory();
    sf.playMp3("song name");

在JButton上点击

我是线程新手,所以如果这有明显的解决方案我会事先道歉!

2 个答案:

答案 0 :(得分:1)

听起来像是你一次性点击多次点击事件而不是一次。一点点日志记录应验证这一点。你的方法对竞争条件很开放。

这两个事件可以如此接近,当一个检查运行它时,看到!running as true。在此之前可以执行running = true,第二个事件也会看到!running as true并输入if子句。然后他们将运行设置为true并生成一个线程来播放mp3。

您需要做的是使方法同步。

public synchronized void playMP3(String name)

http://docs.oracle.com/javase/tutorial/essential/concurrency/syncmeth.html

  

如果count是SynchronizedCounter的一个实例,那么就这样做   方法同步有两个影响:

     
      
  • 首先,对同一对象的两个同步方法的调用不可能进行交错。当一个线程正在执行时   对象的同步方法,所有其他调用的线程   同一对象块的同步方法(暂停执行)   直到第一个线程完成对象。
  •   
  • 其次,当同步方法退出时,它会自动建立与之后的任何关系   调用同一对象的同步方法。这个   保证所有人都可以看到对象状态的变化   线程。
  •   

为了澄清我的上一条评论,这是一个测试程序,显示应该放置running = false。

public class Test {

  public static boolean running = false;

  public synchronized void runner() {
    if(!running) {
      running = true;
      System.out.println("I'm running!");
      new Thread() {
        public void run() {
          for(int i=0; i<10000; i++) {} // Waste some time
          running = false; // This is only changed once the thread completes its execution.
        }
      }.start();
    } else {
      System.out.println("Already running.");
    }
  }

  public static void main(String[] args) {
    Test tester = new Test();
    tester.runner();
    tester.runner(); // The loop inside the Thread should still be running so this should fail.
    for(int i=0; i<20000; i++) {} // Waste even more time.
    tester.runner(); // The loop inside the Thread should be done so this will work.
  }
}

输出:

I'm running! 
Already running. 
I'm running!

自从我使用Swing以来已经多年了,并且忘记了它的事件调度程序是单线程的。所以你的问题比竞争条件更有可能发生。从一开始就把事情写成线程安全仍然没有什么坏处,因为它让你习惯了它并且这样思考。

使用synchronized方法的明确警告......如果只需要对方法的一小部分进行同步,那么性能可能会很糟糕。在这种情况下,您的整个方法需要是线程安全的。

如果只有一小部分需要线程安全,则需要使用synchronized块。

每个实例的线程安全:

public class myClass {
   public void myFunc() {
      // bunch of code that doesn't need to be thread safe.
      synchronized(this) {
         // Code that needs to be thread safe per instance
      }
      // More code that doesn't need thread safety.
   }
}

所有实例的线程安全。

public class myClass {
   static Object lock = new Object();
   public void myFunc() {
      // bunch of code that doesn't need to be thread safe.
      synchronized(lock) {
         // Code that needs to be thread safe across all instances.
      }
      // More code that doesn't need thread safety.
   }
}

静态方法中的线程安全。

public class myClass {
   public static void myFunc() {
      // bunch of code that doesn't need to be thread safe.
      synchronized(MyClass.class) {
         // Code that needs to be thread safe.
      }
      // More code that doesn't need thread safety.
   }
}

可能比你想要的更多的信息,但我刚看到线程编程的教学次数很多很多次。

答案 1 :(得分:0)

您需要在开始播放mp3之前立即拨打JButton.setEnabled(false);,然后在播放完mp3后拨打JButton.setEnabled(true);

显然,您应该用按钮的对象替换JButton(例如:playButton.setEnabled())。