Java Callback 实现线程切换以及与Kotlin原理关系

发布于:2025-08-15 ⋅ 阅读:(19) ⋅ 点赞:(0)

案例

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() {
            @Override
            public void onSuccess(String result) {
                System.out.println("【回调结果】" + result + " - 线程: " + Thread.currentThread().getName());
            }

            @Override
            public void onFailure(Exception error) {
                System.err.println("【回调错误】" + error.getMessage());
            }

            @Override
            public 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();
}

回调机制的优缺点

优点:

  1. 明确的异步操作分离

  2. 支持多状态回调(成功/失败/进度)

  3. 兼容各种 Java 版本

  4. 线程切换逻辑清晰可见

缺点:

  1. 嵌套回调导致"金字塔"代码结构

  2. 错误处理分散在不同回调中

  3. 需要手动管理线程切换

  4. 回调接口定义繁琐(需创建多个接口)

与 Kotlin 协程对比

特性 Java 回调 Kotlin 协程
代码结构 嵌套回调 线性同步风格
线程切换 手动使用 Handler 自动通过 Dispatchers
错误处理 分散在各回调 集中 try-catch
并发控制 需手动同步 async/await 简化
内存开销 多个回调对象 共享状态机
学习曲线 简单直接 概念较复杂

关键区别:协程本质上也是基于回调机制,但通过编译器将回调转换为状态机,使代码保持线性结构。回调是显式线程切换,协程是隐式线程切换。


网站公告

今日签到

点亮在社区的每一天
去签到