Future、RunnableFuture、Callable、FutureTask的使用

1 Future接口

主要用于定义接受异步执行的结果,我们下面主要看他的实现类。参看5

public interface Future<V> {

    boolean cancel(boolean mayInterruptIfRunning);

    boolean isCancelled();

    boolean isDone();

    V get() throws InterruptedException, ExecutionException;

    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

2 RunnableFuture接口

该接口继承了Future和Runnable。则具备两者的特性。

public interface RunnableFuture<V> extends Runnable, Future<V> {
    void run();
}

3 Callable接口

某些情况下,我们需要得到异步线程执行的结果,那Runnable此时不能满足我们的需求,java为我们提供了另一个接口Callable。与Runnable不同的是,实现该接口的类只能由线程池进行调用,无法使用Thread进行调用。

public interface Callable<V> {
    V call() throws Exception;
}

4 AbstractExecutorService的submit方法

线程的execute方法只能执行Runnable的子类。
为了能获取到线程的执行结果,我们需要使用到submit方法,该方法会返回一个Future对象。submit有三个重载方法。

    public Future<?> submit(Runnable task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<Void> ftask = newTaskFor(task, null);
        execute(ftask);
        return ftask;
    }
    public <T> Future<T> submit(Runnable task, T result) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task, result);
        execute(ftask);
        return ftask;
    }
    public <T> Future<T> submit(Callable<T> task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task);
        execute(ftask);
        return ftask;
    }

三个重载方法的逻辑也都非常简单,就是创建一个RunnableFuture的对象,然后调用execute方法。了解过线程池的都知道,最终是执行的run方法,后面我们一起看一下FutureTask的run方法。

    protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
        return new FutureTask<T>(runnable, value);
    }
    protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
        return new FutureTask<T>(callable);
    }

5 FutureTask类

5.1 构造方法

入参为Callable对象

    public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
    }

入参为Runnable对象和返回结果

    public FutureTask(Runnable runnable, V result) {
        this.callable = Executors.callable(runnable, result);
        this.state = NEW;       // ensure visibility of callable
    }
    public static <T> Callable<T> callable(Runnable task, T result) {
        if (task == null)
            throw new NullPointerException();
        return new RunnableAdapter<T>(task, result);
    }
    static final class RunnableAdapter<T> implements Callable<T> {
        final Runnable task;
        final T result;
        RunnableAdapter(Runnable task, T result) {
            this.task = task;
            this.result = result;
        }
        public T call() {
            task.run();
            return result;
        }
    }

从上面可以看出,该构造方法最终也是创建了一个Callable对象,并实现call方法,在call方法中调用了业务的run方法来实现最终的业务调用,并且call方法返回传入的result。
注意区分这里的run方法和FutureTask自身的run方法

5.2 run方法

这里的run方法,是线程池最终调用的方法,这里执行了call方法,并将call方法的返回结果存到outcome这个全局变量中,通过get方法获取。也就是通过FutureTask获取任务的返回值。

public void run() {
		//当前task状态不是新建,直接返回
        if (state != NEW ||
            !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                         null, Thread.currentThread()))
            return;
        try {
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);
                }
                if (ran)
                    set(result);
            }
        } finally {
            // runner must be non-null until state is settled to
            // prevent concurrent calls to run()
            runner = null;
            // state must be re-read after nulling runner to prevent
            // leaked interrupts
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
    }

6 总结

在这里插入图片描述

7 实际使用

public static void main(String[] args) throws ExecutionException, InterruptedException {
        //创建线程池
        ThreadPoolExecutor executorService = new ThreadPoolExecutor(5, Integer.MAX_VALUE,
        60L, TimeUnit.SECONDS,
                new SynchronousQueue<>());
        //存储FutrueTask结果
        ArrayList<Future<Integer>> taskList = new ArrayList<>();
        for(int i=0;i<5;i++){
            //执行任务
            Future<Integer> task = executorService.submit(new Callable<Integer>() {
                @Override
                public Integer call() throws Exception {
                    //这里可以执行具体得业务并返回
                    return 1;
                }
            });
            taskList.add(task);
        }
        int total = 0;
        //处理多线程返回得结果集,get方法回等到线程池执行完,或者抛出异常,这里不必通过shutdown来获取最终结果
        for(Future<Integer> future : taskList){
            Integer integer = future.get();
            total+=integer;
        }
        System.out.println(total);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值