Java Callback 实现线程切换以及与Kotlin原理关系
案例
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;// 1. 定义回调接口
public interface ThreadSwitchCallback {void onSuccess(String result); // 成功回调void onFailure(Exception error); // 失败回调void onProgress(int progress); // 进度更新回调
}// 2. 模拟耗时任务执行器
public class AsyncTaskExecutor {private final ExecutorService threadPool = Executors.newFixedThreadPool(2);// 3. 执行异步任务(接受回调参数)public void executeTask(final String input, final ThreadSwitchCallback callback) {threadPool.execute(() -> {try {// 在工作线程执行耗时操作for (int i = 0; i <= 100; i += 10) {Thread.sleep(200); // 模拟工作callback.onProgress(i); // 进度更新回调}// 模拟处理结果String result = "Processed: " + input.toUpperCase();// 4. 切换到主线程(UI线程)回调结果switchToMainThread(() -> callback.onSuccess(result));} catch (Exception e) {// 5. 错误处理(切换到主线程)switchToMainThread(() -> callback.onFailure(e));}});}// 6. 模拟切换到主线程的方法private void switchToMainThread(Runnable action) {// 在实际Android中应使用 new Handler(Looper.getMainLooper()).post(action)// 这里使用简单模拟new Thread(() -> {try {Thread.sleep(50); // 模拟线程切换延迟System.out.println("【切换到主线程】");action.run();} catch (InterruptedException e) {e.printStackTrace();}}).start();}
}// 7. 主程序(模拟Android UI线程)
public class CallbackDemo {public static void main(String[] args) {System.out.println("【主线程】启动 - " + Thread.currentThread().getName());AsyncTaskExecutor executor = new AsyncTaskExecutor();// 8. 创建回调实现ThreadSwitchCallback callback = new ThreadSwitchCallback() {@Overridepublic void onSuccess(String result) {System.out.println("【回调结果】" + result + " - 线程: " + Thread.currentThread().getName());}@Overridepublic void onFailure(Exception error) {System.err.println("【回调错误】" + error.getMessage());}@Overridepublic void onProgress(int progress) {System.out.println("【进度更新】" + progress + "% - 线程: " + Thread.currentThread().getName());}};// 9. 执行异步任务System.out.println("【主线程】启动异步任务");executor.executeTask("Hello Callback", callback);// 10. 主线程继续执行其他任务System.out.println("【主线程】继续执行其他任务...");// 保持程序运行(模拟Android生命周期)try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}}
}
运行结果示例
【主线程】启动 - main
【主线程】启动异步任务
【主线程】继续执行其他任务...
【进度更新】0% - 线程: Thread-0
【进度更新】10% - 线程: Thread-0
【进度更新】20% - 线程: Thread-0
【进度更新】30% - 线程: Thread-0
【进度更新】40% - 线程: Thread-0
【进度更新】50% - 线程: Thread-0
【进度更新】60% - 线程: Thread-0
【进度更新】70% - 线程: Thread-0
【进度更新】80% - 线程: Thread-0
【进度更新】90% - 线程: Thread-0
【进度更新】100% - 线程: Thread-0
【切换到主线程】
【回调结果】Processed: HELLO CALLBACK - 线程: Thread-1
核心机制解析
1. 回调接口定义
public interface ThreadSwitchCallback {void onSuccess(String result);void onFailure(Exception error);void onProgress(int progress);
}
定义线程切换后需要执行的操作
包含成功、失败、进度更新三种回调类型
2. 线程切换关键实现
private void switchToMainThread(Runnable action) {new Thread(() -> {Thread.sleep(50); // 模拟线程切换延迟System.out.println("【切换到主线程】");action.run(); // 在主线程执行回调}).start();
}
回调机制的优缺点
优点:
明确的异步操作分离
支持多状态回调(成功/失败/进度)
兼容各种 Java 版本
线程切换逻辑清晰可见
缺点:
嵌套回调导致"金字塔"代码结构
错误处理分散在不同回调中
需要手动管理线程切换
回调接口定义繁琐(需创建多个接口)
与 Kotlin 协程对比
特性 | Java 回调 | Kotlin 协程 |
---|---|---|
代码结构 | 嵌套回调 | 线性同步风格 |
线程切换 | 手动使用 Handler | 自动通过 Dispatchers |
错误处理 | 分散在各回调 | 集中 try-catch |
并发控制 | 需手动同步 | async/await 简化 |
内存开销 | 多个回调对象 | 共享状态机 |
学习曲线 | 简单直接 | 概念较复杂 |
关键区别:协程本质上也是基于回调机制,但通过编译器将回调转换为状态机,使代码保持线性结构。回调是显式线程切换,协程是隐式线程切换。