Java中结合BasicPlayer的线程问题:实时获取播放器状态
我来帮你解决这个线程同步和BasicPlayer状态监控的问题,先梳理下你当前代码里的核心问题,再给你两种可行的解决方案:
核心问题分析
你当前代码里最致命的问题是:在play()方法中,你启动了一个全新的Player实例线程——new Thread(new Player()).start(),这个新线程和正在播放音频的Player完全不是同一个对象,自然监控不到正确的播放状态。这不是单纯加同步方法能解决的,得先把实例统一起来。
另外,直接轮询状态不是最高效的方式,BasicPlayer本身提供了监听器接口,可以主动监听播放完成事件,比轮询更优雅。下面分两种方式给你修复:
方式一:修复轮询线程的实例问题
先调整代码,让监控线程属于当前Player实例,确保它监控的是正在播放的同一个BasicPlayer对象:
import javazoom.jl.player.BasicPlayer; import javazoom.jl.player.BasicPlayerException; import java.net.MalformedURLException; import java.net.URL; public class Player implements Runnable { private String song; private boolean comp = false; private final String path; private final BasicPlayer player; public Player() { player = new BasicPlayer(); path = System.getProperty("user.dir") + "/src/Music/"; } public void setSongName(String songName) { song = songName; } public String getSongName() { return song; } public void play() { try { player.open(new URL("file:///" + path + song)); player.play(); // 启动当前实例的监控线程,而不是新建Player对象 new Thread(this).start(); } catch (BasicPlayerException | MalformedURLException e) { e.printStackTrace(); } } // 把状态监控逻辑放到run方法里 @Override public void run() { try { // 循环检查状态,直到播放完成 while (!isComplete()) { Thread.sleep(500); // 每隔500ms检查一次,避免过度占用CPU } setComp(true); // 这里可以直接添加自动播放下一首的逻辑 System.out.println("当前歌曲播放完成,准备播放下一首"); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } private boolean isComplete() { // 同步player对象,确保状态读取的线程安全 synchronized (player) { // 推荐用BasicPlayer的常量代替硬编码的2,可读性更强 return player.getStatus() == BasicPlayer.STOPPED; } } public synchronized boolean getComplete() { return comp; } public synchronized void setComp(boolean comp) { this.comp = comp; } }
关键修改点:
- 把
new Thread(new Player()).start()改成new Thread(this).start(),用当前Player实例作为Runnable,确保监控的是同一个播放实例 - 把状态检查逻辑移到
run()方法中,避免重复创建对象 - 用
BasicPlayer.STOPPED常量代替硬编码的2,代码更易维护 - 添加
Thread.sleep(500)减少轮询的CPU消耗
方式二:使用BasicPlayerListener监听播放事件(更优雅)
轮询不是最优解,BasicPlayer支持监听器模式,可以主动通知播放完成事件,代码更简洁高效:
import javazoom.jl.player.BasicPlayer; import javazoom.jl.player.BasicPlayerEvent; import javazoom.jl.player.BasicPlayerException; import javazoom.jl.player.BasicPlayerListener; import java.net.MalformedURLException; import java.net.URL; import java.util.Map; public class Player implements BasicPlayerListener { private String song; private boolean comp = false; private final String path; private final BasicPlayer player; public Player() { player = new BasicPlayer(); // 给Player添加监听器,监听播放事件 player.addBasicPlayerListener(this); path = System.getProperty("user.dir") + "/src/Music/"; } public void setSongName(String songName) { song = songName; } public void play() { try { player.open(new URL("file:///" + path + song)); player.play(); } catch (BasicPlayerException | MalformedURLException e) { e.printStackTrace(); } } // 监听播放完成事件(EOM = End of Media) @Override public void stateUpdated(BasicPlayerEvent event) { if (event.getCode() == BasicPlayerEvent.EOM) { setComp(true); System.out.println("当前歌曲播放完成,准备播放下一首"); // 在这里直接调用下一首的播放逻辑即可 } } // 下面是监听器的其他默认实现方法,按需调整 @Override public void opened(Object stream, Map properties) {} @Override public void progress(int bytesread, long microseconds, byte[] pcmdata, Map properties) {} @Override public void setController(BasicPlayer controller) {} public synchronized boolean getComplete() { return comp; } public synchronized void setComp(boolean comp) { this.comp = comp; } }
优势:
- 不需要额外的轮询线程,由BasicPlayer主动通知播放完成
- 代码更简洁,CPU消耗更低
- 能精准捕捉到播放结束的时机
主程序同步示例
在你的Scanner输入线程中,只需要和这个Player实例交互即可。比如:
import java.util.Scanner; public class Main { public static void main(String[] args) { Player player = new Player(); Scanner scanner = new Scanner(System.in); while (true) { System.out.println("输入歌曲名播放(输入exit退出):"); String input = scanner.nextLine(); if ("exit".equalsIgnoreCase(input)) { break; } player.setSongName(input); player.play(); // 如果用轮询方式,可以在这里等待播放完成 // while (!player.getComplete()) { // try { // Thread.sleep(100); // } catch (InterruptedException e) { // e.printStackTrace(); // } // } } scanner.close(); } }
内容的提问来源于stack exchange,提问作者Archishmaan P
相关产品推荐
相关产品推荐

