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
相关产品推荐
相关产品推荐

