Java 如何阻止mp3文件一次播放多次?
我正试图通过按下按钮或从列表中选择播放mp3文件(我已经成功地做到了)。然而,我似乎无法阻止歌曲在同一个按钮上播放多次 我想做的是在一个新线程中播放歌曲,禁用再次播放歌曲,直到线程关闭,然后允许再次播放 我的代码如下:Java 如何阻止mp3文件一次播放多次?,java,multithreading,mp3,Java,Multithreading,Mp3,我正试图通过按下按钮或从列表中选择播放mp3文件(我已经成功地做到了)。然而,我似乎无法阻止歌曲在同一个按钮上播放多次 我想做的是在一个新线程中播放歌曲,禁用再次播放歌曲,直到线程关闭,然后允许再次播放 我的代码如下: public class SoundFactory { private Player player; private static boolean running = false; private String getFile(String name) { Strin
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上单击
我是线程新手,所以如果这有一个明显的解决方案,我会提前道歉 您需要调用
JButton.setEnabled(false)在开始播放mp3之前,单击code>,然后调用JButton.setEnabled(true)代码>当mp3播放完毕时
显然,您应该用按钮的对象(例如:playButton.setEnabled()
)替换JButton
。我觉得您一次触发多个单击事件,而不是一个。一点日志记录应该可以验证这一点。你的方法是完全开放的比赛条件
这两个事件可以如此紧密地联系在一起,以至于当一个人检查运行它时,就会看到!像真的一样跑。在那之前一个人可以做running=true,第二个事件也会看到!运行为true并输入if子句。然后它们都将running设置为true,并生成一个线程来播放mp3
您需要做的是使您的方法同步
public synchronized void playMP3(String name)
如果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.
}
}
我使用Swing已经很多年了,忘记了它的事件分派器是单线程的。因此,你的问题更可能是这种情况,而不是比赛条件。从一开始就开始写线程安全的东西仍然没有什么坏处,因为这会让你习惯它,并以这种方式思考
关于使用同步方法的明确警告。。。如果只需要同步方法的一小部分,则会对性能造成严重影响。在这种情况下,整个方法需要是线程安全的
如果只有一小部分需要线程安全,则需要使用同步块
每个实例的线程安全性:
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.
}
}
可能比您想要的信息要多得多,但我刚刚看到线程编程的教学效果太差了很多很多次。我应该补充一点,如果这能解决您的问题,那么禁用和启用按钮将是不必要的。我想我明白了为什么同步的
方法在这里很有用,但是running=false代码>行是以任何方式执行的,所以没有任何东西可以阻止您创建另一个线程?即使使用synchronized
方法,我仍然可以多次(甚至在几秒钟后)按下按钮,歌曲将同时播放多次!我现在注意到running=false在Thread.run()方法之外。您需要将其移动到run方法中,使其成为线程的一部分。在它所在的位置,线程开始执行自己的事情,并立即在playm3方法中继续执行,即running=false。因此,此时MP3仍在播放,但运行现在又是错误的。感谢您花时间撰写如此清晰和广泛的回复。对我这样的初学者来说真的很有用!:)他很可能有比赛的情况。在这种情况下,更改按钮的启用状态不会起任何作用。明智地使用synchronized是正确的做法。
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.
}
}