You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java中javax.sound.sampled.Clip运行一段时间后停止工作

问题分析与解决方案

核心原因

你遇到的问题本质是音频线路资源耗尽,而非文件格式问题。每次调用AudioSystem.getClip()都会创建一个新的Clip实例,而系统能同时打开的音频线路数量是有限的。短时间内高频调用(每秒两次)会快速耗尽可用线路,此时再创建新Clip就会抛出LineUnavailableException,且由于资源不足的异常上下文混乱,会误报成“格式不支持”。

即使缓存了音频数据,只要每次都创建新的Clip实例且不及时释放资源,问题依然会出现——因为消耗的是音频线路资源,不是文件加载的内存资源。

解决方案

1. 播放结束后主动释放Clip资源

给Clip添加LineListener,在播放完成(STOP事件)后调用close()释放线路资源,及时回收资源避免耗尽:

public static void playSound(String path) {
    logger.info("Playing " + path);
    Clip clip = null;
    try {
        clip = AudioSystem.getClip();
        AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(new BufferedInputStream(new FileInputStream(path)));
        clip.open(audioInputStream);
        // 添加监听器,播放结束后关闭Clip
        clip.addLineListener(event -> {
            if (event.getType() == LineEvent.Type.STOP) {
                clip.close();
            }
        });
        clip.start();
    } catch (LineUnavailableException e) {
        System.err.println("音频线路资源耗尽,无法播放 " + path);
        e.printStackTrace();
    } catch (UnsupportedAudioFileException | IOException e) {
        e.printStackTrace();
    }
}

2. 复用Clip实例(针对重复播放的音频)

如果某些音频需要重复播放,可以提前初始化并缓存Clip实例,播放前重置状态而非创建新实例:

// 缓存已初始化的Clip
private static final Map<String, Clip> CLIP_CACHE = new ConcurrentHashMap<>();

public static void playCachedSound(String path) throws IOException, UnsupportedAudioFileException, LineUnavailableException {
    Clip clip = CLIP_CACHE.computeIfAbsent(path, key -> {
        try {
            Clip newClip = AudioSystem.getClip();
            AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(new File(key));
            newClip.open(audioInputStream);
            return newClip;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    });
    // 重置到起始位置并播放
    clip.stop();
    clip.setFramePosition(0);
    clip.start();
}

3. 控制并发播放数量

如果需要同时播放多个不同音频,可以使用信号量限制并发的Clip数量,避免超过系统线路上限:

// 限制最多同时播放2个音频(根据系统实际情况调整)
private static final Semaphore SEMAPHORE = new Semaphore(2);

public static void playSoundWithLimit(String path) {
    logger.info("Playing " + path);
    new Thread(() -> {
        try {
            SEMAPHORE.acquire();
            Clip clip = AudioSystem.getClip();
            AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(new BufferedInputStream(new FileInputStream(path)));
            clip.open(audioInputStream);
            clip.addLineListener(event -> {
                if (event.getType() == LineEvent.Type.STOP) {
                    clip.close();
                    SEMAPHORE.release();
                }
            });
            clip.start();
        } catch (Exception e) {
            SEMAPHORE.release();
            e.printStackTrace();
        }
    }).start();
}

额外注意事项

  • Ubuntu下的PulseAudio默认对同时打开的音频流有数量限制,及时释放资源是关键。
  • OpenJDK的AudioSystem实现依赖系统底层音频服务,可通过pulseaudio --check命令验证服务是否正常运行。

内容的提问来源于stack exchange,提问作者dVNE

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 14:22:32