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

如何在不同ActionListener中调用同一线程实现音乐播放/停止控制

你猜测的「停止音乐需要在播放按钮运行的同一线程中调用对应方法」的思路不完全正确,stop方法可以跨线程调用,无法停止的核心原因是:

  1. 你的cl.play()方法是阻塞执行的,内部没有定期检查停止、暂停的状态标记,即使其他线程修改了停止标记,播放逻辑也感知不到,会继续执行。
  2. 你每次点击播放都会新建独立线程,没有统一管理播放线程,多次点击播放后会同时存在多个播放线程,更难统一控制。
实现方案

1. 修改播放控制类,增加线程可见的状态标记

给cl对应的类添加volatile修饰的状态标记,保证多线程修改的可见性,播放逻辑中循环检查状态响应控制指令:

public class 你的CL类名 {
    // 播放、暂停状态标记,volatile保证多线程修改后其他线程立即可见
    private volatile boolean isPlaying = false;
    private volatile boolean isPaused = false;

    public void play() {
        isPlaying = true;
        isPaused = false;
        // 播放主循环,每次循环都检查状态
        while (isPlaying) {
            if (isPaused) {
                // 暂停状态休眠10ms,避免空转占用CPU
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    return;
                }
                continue;
            }
            // 你原有读取音频帧、输出音频的播放逻辑写在这里
            // 注意单次循环执行时间不要太长,否则停止/暂停响应会有延迟
        }
        // 退出循环后执行资源释放,比如关闭音频流、重置播放进度
        releaseResource();
    }

    public void stop() {
        isPlaying = false;
        isPaused = false;
    }

    public void pause() {
        isPaused = true;
    }

    public void resume() {
        isPaused = false;
    }

    private void releaseResource() {
        // 你的资源释放逻辑
    }
}

2. 统一管理播放线程,避免重复创建

把播放线程提为GUI类的成员变量,避免每次点击播放都新建线程:

// GUI类的成员变量,统一持有播放线程实例
private Thread playThread;

ActionListener bl2 = new ActionListener() { // 播放按钮
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("listener1" + Thread.currentThread().getName());
        System.out.println("beep");
        // 已有播放线程在运行就跳过,避免重复播放
        if (playThread != null && playThread.isAlive()) {
            return;
        }
        Runnable runnable = () -> cl.play();
        playThread = new Thread(runnable);
        playThread.start();
    }
};

ActionListener bl3 = new ActionListener() { // 停止按钮
    @Override
    public void actionPerformed(ActionEvent e) {
        cl.stop();
        // 等待播放线程正常退出,避免资源泄漏
        if (playThread != null) {
            try {
                playThread.join();
            } catch (InterruptedException ex) {
                Thread.currentThread().interrupt();
            }
            playThread = null;
        }
    }
};

// 暂停按钮的事件监听实现
ActionListener bl4 = new ActionListener() { // 暂停按钮
    @Override
    public void actionPerformed(ActionEvent e) {
        cl.pause();
    }
};

// 恢复播放按钮的事件监听实现,可与暂停按钮做二合一切换
ActionListener bl5 = new ActionListener() { // 恢复播放按钮
    @Override
    public void actionPerformed(ActionEvent e) {
        cl.resume();
    }
};
注意事项
  • 不要使用Java原生废弃的Thread.stop()方法强制终止线程,该方法会导致资源无法正常释放,用状态标记通知线程主动退出的方式更安全。
  • 如果你使用Java Sound API的Clip类实现播放,直接在cl.stop()内部调用clip.stop()、clip.close()即可停止,无需自己实现状态循环。
  • 所有Swing GUI的修改操作必须在EDT事件调度线程执行,不要在自定义的播放线程中修改界面元素。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 09:36:04