Callable、FutureTask及手写实现

创建线程的两种方式:Thread和Runnable,但它们都有一个缺点:无法获取返回值

如果需要进行异步运算,而且需要获取运算的结果值,可以使用Callable和FutureTask。

FutureTask API

  • boolean isCancelled()
    是否取消。

  • boolean isDone()
    是否计算结束。

  • boolean cancel(boolean mayInterruptIfRunning)
    取消计算,mayInterruptIfRunning(运行时允许是否中断)。

  • V get()
    获取计算结果,会阻塞。

  • V get(long timeout, TimeUnit unit)
    获取计算结果,设置一个超时时间。

使用例子

public class CallableDemo implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
        int sum = 0;
        for (int i = 0; i < 100; i++) {
            sum += i;
        }
        return sum;
    }

    public static void main(String[] args) throws Exception {
        CallableDemo demo = new CallableDemo();
        //不要直接get(),会无限阻塞,因为没有开启线程去计算
        FutureTask<Integer> task = new FutureTask(demo);

        new Thread(task).start();
        Integer taskResult = task.get();
        System.out.println("result:"+taskResult);
        //result:4950
    }
}

FutureTask创建后,在开启线程计算前不要直接调用get(),否则会无限阻塞下去。

手写实现

/**
 * @Author: 潘
 * @Date: 2019/11/6 15:10
 * @Description: 手写实现Callable
 */
@FunctionalInterface
public interface MyCallable<V> {
    V call();
}

class MyTask<V> implements Runnable{
    private MyCallable<V> myCallable;
    private V v;

    public MyTask(MyCallable<V> myCallable) {
        this.myCallable = myCallable;
    }

    @Override
    public synchronized void run() {
        v = myCallable.call();
        //计算完毕 通知线程
        notifyAll();
    }

    public synchronized V get(){
        while (true) {
            if (v != null) {
                return v;
            }
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        MyCallable<Integer> callable = () -> {
            int sum = 0;
            for (int i = 0; i < 10; i++) {
                //模拟复杂计算耗时
                SleepUtil.sleep(100);
                sum+=i;
            }
            return sum;
        };
        MyTask<Integer> task = new MyTask<>(callable);
        //开启线程,callable开始计算
        new Thread(task).start();
        System.out.println("MyCallable开始进行计算...");

        //main线程还可进行其他操作
        for (int i = 0; i < 3; i++) {
            System.out.println("main线程继续其他操作:" + i);
        }

        System.out.println("main线程准备获取结果,此时开始阻塞...");
        //在需要时获取结果,未计算完会阻塞,计算完会直接返回
        Integer result = task.get();
        System.out.println("MyCallable 结果:"+result);
    }
}

输出如下:

MyCallable开始进行计算...
main线程继续其他操作:0
main线程继续其他操作:1
main线程继续其他操作:2
main线程准备获取结果,此时开始阻塞...
MyCallable 结果:45
发布了100 篇原创文章 · 获赞 23 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/qq_32099833/article/details/103127807