Java Callable任务

由于有获取异步任务执行结果的需求,所以java又扩展了一种Callable任务。

@FunctionalInterface
public interface Callable<V> {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}

一个典型的用法是:

public class Main {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        Future<Integer> future = executorService.submit(() -> {
            // 一个异步任务
            return 0;
        });
        try {
            // 获取异步结果
            System.out.println(future.get());
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }
}

那么get是如何获取异步任务的结果的呢?
秘密就在FutureTask和AbstractExecutorService里。
经过这两个类的联动,就在Runnable任务的基础上,扩展出了Callable任务。

首先看,AbstractExecutorService的submit和newTaskFor:

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

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

提交的Callable任务,经FutureTask封装后,真正异步执行的是FutureTask的run方法,最后submit返回的其实也是FutureTask对象。然后调用get方法获取异步任务的结果,其实调用的也是FutureTask的get方法。

那么重点就是,FutureTask是如何在run方法里执行异步任务,并在get方法里获取异步任务的结果?

其实靠的就是两者共享的一个中间变量,靠这个中间变量中转异步任务的执行结果。

    public void run() {
        if (state != NEW ||
            !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                         null, Thread.currentThread()))
            return;
        try {
            // 这个callable就是newTaskFor时传进来的异步任务
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    // 执行Callable的call方法
                    result = c.call();
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    // 如果发生异常,set异常
                    setException(ex);
                }
                if (ran)
                    //   任务没有异常,set执行结果
                    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);
        }
    }

call的执行有两种情况,1. 发生异常,通过setException方法设置结果。2. 正常执行,通过set方法设置结果。

    // outcome就是异步结果的中转变量
    private Object outcome;

    protected void setException(Throwable t) {
        if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
            // 把Throwable对象放到outcome里
            outcome = t;
            // 终态置为EXCEPTIONAL
            UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state
            // 唤醒所有阻塞在get方法上的线程
            finishCompletion();
        }
    }

    protected void set(V v) {
        if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
            // 正常的执行结果放入outcome
            outcome = v;
            // 终态置为NORMAL
            UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
            // 唤醒所有阻塞在get方法上的线程
            finishCompletion();
        }
    }

再来看看get方法

    public V get() throws InterruptedException, ExecutionException {
        int s = state;
        if (s <= COMPLETING)
            // 异步任务还没完成,阻塞当前想要获取结果的线程
            s = awaitDone(false, 0L);
        // 返回异步结果
        return report(s);
    }

    // 参数s是任务执行状态
    private V report(int s) throws ExecutionException {
        // 根据outcome里的执行结果和任务执行状态,返回正常结果或抛出异常
        Object x = outcome;
        if (s == NORMAL)
            return (V)x;
        if (s >= CANCELLED)
            throw new CancellationException();
        throw new ExecutionException((Throwable)x);
    }

总结:对于Callable任务来说,其实真正异步的还是Runnable任务,Callable只是对Runnable的封装,通过中间变量,让我们可以方便的获取异步执行的结果。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中的Callable是一个接口,它可以让我们在执行某个任务时返回一个结果,并且可以抛出异常。与Runnable接口不同的是,Callable接口中的call()方法可以返回值,并且可以抛出异常,而Runnable接口中的run()方法没有返回值,也不能抛出异常。 在使用Callable时,我们需要借助ExecutorService来执行任务。ExecutorService是一个Java线程池框架,它可以管理线程池的创建、销毁和复用。我们可以通过调用ExecutorService的submit()方法来提交Callable任务,submit()方法会返回一个Future对象,我们可以通过Future对象来获取任务的执行结果或者取消任务的执行。 下面是一个使用Callable和ExecutorService的示例代码: ``` import java.util.concurrent.*; public class CallableExample { public static void main(String[] args) { ExecutorService executor = Executors.newSingleThreadExecutor(); Callable<Integer> task = () -> { try { TimeUnit.SECONDS.sleep(1); return 123; } catch (InterruptedException e) { throw new IllegalStateException("task interrupted", e); } }; Future<Integer> future = executor.submit(task); System.out.println("future done? " + future.isDone()); Integer result = null; try { result = future.get(); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } System.out.println("future done? " + future.isDone()); System.out.println("result: " + result); executor.shutdown(); } } ``` 在上面的代码中,我们创建了一个Callable任务task,它会在执行后返回整数123。我们通过ExecutorService的submit()方法来提交任务,并且通过Future对象来获取任务的执行结果。由于任务执行需要一定的时间,我们在获取结果之前先通过future.isDone()方法检查任务是否已经完成。最后,我们关闭了ExecutorService线程池。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值