Java多线程系列--掌握Future,轻松获取异步任务结果

本文探讨了Java中Runnable接口的局限性,引出了为异步处理而设计的Future接口。通过示例展示了如何使用FutureTask进行异步计算,并介绍了Future模式、Master-Worker模式等多线程业务模式,帮助开发者更好地理解和应用Java的多线程机制。
摘要由CSDN通过智能技术生成

Runnable的局限性

在前文中我们谈到,通过编码实现Runnable接口,将获得具有边界性的 "任务",在指定的线程(或者线程池)中运行。

重新观察该接口,不难发现它并没有方法返回值:

public interface Runnable {
    void run();
}
复制代码

在JDK1.5之前,想利用任务的执行结果,需要小心的操作线程访问临界区资源。使用 回调 进行解耦是非常不错的选择。

练手小Demo -- 回顾既往文章知识

注意,为了减少篇幅使用了lambda,但jdk1.5之前并不支持lambda

将计算任务分离到其他线程执行,再回到主线程消费结果

我们将计算、IO等耗时任务丢到其他线程,让主线程专注于自身业务, 假想它在接受用户输入以及处理反馈,但我们略去这一部分

我们可以设计出类似下面的代码:

虽然它还有很多不合理之处值得优化,但也足以用于演示

class Demo {
    static final Object queueLock = new Object();
    static List<Runnable> mainQueue = new ArrayList<>();
    static boolean running = true;

    static final Runnable FINISH = () -> running = false;

    public static void main(String[] args) {
        synchronized (queueLock) {
            mainQueue.add(Demo::onStart);
        }
        while (running) {
            Runnable runnable = null;
            synchronized (queueLock) {
                if (!mainQueue.isEmpty())
                    runnable = mainQueue.remove(0);
            }
            if (runnable != null) {
                runnable.run();
            }
            Thread.yield();
        }
    }

    public static void onStart() {
        //...
    }

    public static void finish() {
        synchronized (queueLock) {
            mainQueue.clear();
            mainQueue.add(FINISH);
        }
    }
}
复制代码

再模拟一个计算的线程和任务回调:

interface Callback {
    void onResultCalculated(int result);
}

class CalcThread extends Thread {

    private final Callback callback;

    private final int a;

    private final int b;

    public CalcThread(Callback callback, int a, int b) {
        this.callback = callback;
        this.a = a;
        this.b = b;
    }

    @Override
    public void run() {
        super.run();
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        final int result = a + b;
        System.out.println("threadId" + Thread.currentThread().getId() + ",calc result:" + result + ";" + System.currentTimeMillis());

        synchronized (queueLock) {
            mainQueue.add(() -> callback.onResultCalculated(result));
        }
    }
}
复制代码

填充一下onStart业务:

class Demo {
    public static void onStart() {
        System.out.println("threadId" + Thread.currentThread().getId() + ",onStart," + System.currentTimeMillis());

        new CalcThread(result -> {
            System.out.println("threadId" + Thread.currentThread().getId() + ",onResultCalculated:" + result + ";" + System.currentTimeMillis());
            finish();
        }, 200, 300).start();

    }
}
复制代码

复习:优化为使用Runnable

在前文我们提到,如果业务仅关注任务的执行,并不过于关心线程本身,则可以利用Runnable:

class Demo {
    static class CalcRunnable implements Runnable {

        private final Callback callback;

        private final int a;

        private final int b;

        public CalcRunnable(Callback callback, int a, int b) {
  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值