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

Java中如何让线程任务结束后的回调函数执行在主线程而非工作线程

根本原因

当前你直接在子线程的run()方法内调用回调接口,回调逻辑自然运行在子线程中。纯Java SE环境没有内置的主线程消息调度机制,需要手动实现主线程的任务消费逻辑,才能将回调执行切换到主线程。

实现方案

核心思路是用阻塞队列做任务中转:

  • 定义全局阻塞队列,用来存储待主线程执行的回调任务
  • 子线程完成耗时计算后,将回调逻辑封装为任务提交到队列
  • 主线程循环从队列中拉取任务并执行,即可保证回调运行在主线程

修改后的可运行代码如下:

import java.util.Random;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class ATestThreadClass {
    // 主线程任务队列,所有待主线程执行的任务都存在这里
    private static final BlockingQueue<Runnable> MAIN_THREAD_TASKS = new LinkedBlockingQueue<>();

    public static void main(String[] args) throws InterruptedException {
        // 启动子线程执行耗时任务
        new Thread(new RandomRunnable(data -> {
            // 子线程仅提交回调任务到队列,不直接执行回调
            MAIN_THREAD_TASKS.offer(() -> {
                System.out.println("Called on " + Thread.currentThread().getName());
                System.out.println(data.toString());
            });
        })).start();

        // 主线程消费队列任务,可根据业务需求调整循环退出条件
        while (true) {
            Runnable task = MAIN_THREAD_TASKS.take();
            task.run();
            // 示例仅执行一次回调就退出,持续消费可以去掉break
            break;
        }
    }

    static class RandomRunnable implements Runnable {
        private final CallbackInterface callbackInterface;

        public RandomRunnable(CallbackInterface callbackInterface) {
            this.callbackInterface = callbackInterface;
        }

        @Override
        public void run() {
            // 执行耗时任务
            Random random = new Random();
            RandomCallbackData data = new RandomCallbackData();
            data.a = random.nextInt(100);
            data.b = random.getClass().getSimpleName();
            data.c = random.nextLong();
            callbackInterface.callback(data);
        }
    }


    interface CallbackInterface {
        void callback(RandomCallbackData data);
    }

    static class RandomCallbackData {
        public int a;
        public String b;
        public long c;

        @Override
        public String toString() {
            return "RandomCallbackData{" +
                    "a=" + a +
                    ", b='" + b + '\'' +
                    ", c=" + c +
                    '}';
        }
    }
}

运行后输出符合预期,回调运行在主线程:

Called on main
RandomCallbackData{a=32, b='Random', c=487931245562179688}

Process finished with exit code 0

如果主线程本身有其他业务逻辑需要执行,不需要一直阻塞等待任务,可以把阻塞的take()换成非阻塞的poll(),定时检查队列是否有待执行任务即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 20:54:06