Java的异步编程(四):CompletableFuture的静态工厂方法、控制方法

一:构造函数和静态工厂方法

1.方法列表

 a).CompletableFuture提供了丰富的静态构造方法,从线程类型上支持Runnable、Callable,从线程池上支持自己提供的和默认的;

//构造方法
public CompletableFuture() {}

//针对Callable的异步Future静态工厂方法,使用内部的ForkJoinPool
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) ;

//针对Callable的异步Future静态工厂方法,使用自定义的Executor
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor) ;

//针对Runnable的异步Future静态工厂方法,使用内部的ForkJoinPool
public static CompletableFuture<Void> runAsync(Runnable runnable);

//针对Runnable的异步Future静态工厂方法,使用内部的ForkJoinPool
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor) ;

//直接返回一个值固定的Future,比如在提供默认值的场景下
public static <U> CompletableFuture<U> completedFuture(U value) ;

 

2.静态工厂方法的内部实现(以supplyAsync为例)

a.supplyAsync静态工厂方法

    1.supplyAsync的内部是使用AsyncSupply实现的,会对Future的result赋值,和runAsync的内部是使用AsyncRun内部类实现的,不会对result进行赋值;

    2,如下所示,AsyncSupply将Supplier封装成AsyncSupply,然后提交给Executor执行;

public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) {
/*在这里去设置线程池信息,线程池为前文介绍的ForkJoinPool的commonPool,或者是单线程的池子*/
/*所以这里需要注意一下,就是ForkJoinPool的池子,可能被很多地方用*/
        return asyncSupplyStage(asyncPool, supplier);
    }

static <U> CompletableFuture<U> asyncSupplyStage(Executor e,Supplier<U> f) {
        if (f == null) throw new NullPointerException();
        CompletableFuture<U> d = new CompletableFuture<U>();
//把Supplier封装成任务,并执行
        e.execute(new AsyncSupply<U>(d, f));
        return d;
    }

     3.AsyncSupply中的逻辑为,若当前的result为null,则将Supplier.get()的结果赋值给result,若有异常,则将异常封装为AltResult然后赋值给result;


//AsyncSupply的实现
static final class AsyncSupply<T> extends ForkJoinTask<Void>
            implements Runnable, AsynchronousCompletionTask {
        CompletableFuture<T> dep; Supplier<T> fn;
        AsyncSupply(CompletableFuture<T> dep, Supplier<T> fn) {
            this.dep = dep; this.fn = fn;
        }

        public final Void getRawResult() { return null; }
        public final void setRawResult(Void v) {}
        public final boolean exec() { run(); return true; }
/*线程的执行函数*/
        public void run() {
            CompletableFuture<T> d; Supplier<T> f;
            if ((d = dep) != null && (f = fn) != null) {
                dep = null; fn = null;
                if (d.result == null) {
                    try {
/*同步的执行,获取执行结果*/
                        d.completeValue(f.get());
                    } catch (Throwable ex) {
/*出现异常,则将结果设置为异常*/
                        d.completeThrowable(ex);
                    }
                }
/*完成后,通知依赖项处理*/
                d.postComplete();
            }
        }
    }

4.正常和异常的赋值逻辑

//完成时未发生异常,设置其值
/** Completes with a non-exceptional result, unless already completed. */
    final boolean completeValue(T t) {
        return UNSAFE.compareAndSwapObject(this, RESULT, null,
                                           (t == null) ? NIL : t);
    }
//对异常赋值的逻辑
final boolean completeThrowable(Throwable x) {
        return UNSAFE.compareAndSwapObject(this, RESULT, null,
                                           encodeThrowable(x));
    }
//组装异常
static AltResult encodeThrowable(Throwable x) {
        return new AltResult((x instanceof CompletionException) ? x :
                             new CompletionException(x));
    }

 

二:控制类方法

1.判断是否完成isDone()

 如果完成返回true,包括:

//仅仅通过result是否为null来判断,如果已经完成,result会设置值 的
    public boolean isDone() {
        return result != null;
    }    

2.获取结果get()、等待结构完成join()

 二者的区别很细微,一是在抛出的异常是有些不同,另外是在等待任务结果时,get允许中断,join不允许中断;

它们在等待的时候,都用了自旋的机制,一般自旋256;

public T get() throws InterruptedException, ExecutionException {
        Object r;
//如果已经完成,则返回,否则等待结果完成
        return reportGet((r = result) == null ? waitingGet(true) : r);
    }

public T join() {
        Object r;
//如果已经完成,则返回,否则等待结果完成
        return reportJoin((r = result) == null ? waitingGet(false) : r);
    }

/**
* Returns raw result after waiting, or null if interruptible and interrupted.
  在等待后返回运算结果,或者当可被中断、已经中断的情况下,返回null*/
    private Object waitingGet(boolean interruptible) {
        Signaller q = null;
//标记是否已经进入队列,有且仅进入一次
        boolean queued = false;
        int spins = -1;
        Object r;
//不断循环,直到任务完成
        while ((r = result) == null) {
//如果只有一个处理器可用,则进行不断自旋
            if (spins < 0)
                spins = (Runtime.getRuntime().availableProcessors() > 1) ?
                    1 << 8 : 0; // Use brief spin-wait on multiprocessors
            else if (spins > 0) {
                if (ThreadLocalRandom.nextSecondarySeed() >= 0)
                    --spins;
            }
//新建一个signaller,代表当前依赖,并加入队列
            else if (q == null)
                q = new Signaller(interruptible, 0L, 0L);
            else if (!queued)
                queued = tryPushStack(q);
//如果允许中断,且已经中断,则将当前线程移出队列,并返回null
            else if (interruptible && q.interruptControl < 0) {
                q.thread = null;
                cleanStack();
                return null;
            }
//如果当前没被中断,且未完成,则利用managedBlock来管理阻塞,下面会降下这个
            else if (q.thread != null && result == null) {
                try {
                    ForkJoinPool.managedBlock(q);
                } catch (InterruptedException ie) {
//设置当前进程为已中断
                    q.interruptControl = -1;
                }
            }
        }
//如果已经完成,根据当前线程是否中断,返回结果
        if (q != null) {
            q.thread = null;
            if (q.interruptControl < 0) {
                if (interruptible)
                    r = null; // report interruption
                else
                    Thread.currentThread().interrupt();
            }
        }
        postComplete();
        return r;
    }

3.超时获取结果get(long timeout, TimeUnit unit)

 它和get()的区别在于:它如果限定时间内,等不到结果,会异常退出

public T get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException {
        Object r;
        long nanos = unit.toNanos(timeout);
        return reportGet((r = result) == null ? timedGet(nanos) : r);
    }

//等待
    private Object timedGet(long nanos) throws TimeoutException {
//当前线程被中断,直接返回
        if (Thread.interrupted())
            return null;
        if (nanos <= 0L)
            throw new TimeoutException();
        long d = System.nanoTime() + nanos;
        Signaller q = new Signaller(true, nanos, d == 0L ? 1L : d); // avoid 0
        boolean queued = false;
        Object r;
        // We intentionally don't spin here (as waitingGet does) because
        // the call to nanoTime() above acts much like a spin.
        while ((r = result) == null) {
//入队列
            if (!queued)
                queued = tryPushStack(q);
//在下面的manageLock中,会对nanos更新,nanos = deadline - System.nanoTime(),
当其小于0,表示超时
            else if (q.interruptControl < 0 || q.nanos <= 0L) {
                q.thread = null;
                cleanStack();
                if (q.interruptControl < 0)
                    return null;
                throw new TimeoutException();
            }
//管理中断
            else if (q.thread != null && result == null) {
                try {
                    ForkJoinPool.managedBlock(q);
                } catch (InterruptedException ie) {
                    q.interruptControl = -1;
                }
            }
        }
        if (q.interruptControl < 0)
            r = null;
        q.thread = null;
        postComplete();
        return r;
    }

4.取消cancel()

 用于取消任务,将result设置为cancellationException

    public boolean cancel(boolean mayInterruptIfRunning) {
        boolean cancelled = (result == null) &&
            internalComplete(new AltResult(new CancellationException()));
        postComplete();
        return cancelled || isCancelled();
    }

4.查看取消状态isCancelled()

 根据result是否为cancellationException来判断

public boolean isCancelled() {
        Object r;
        return ((r = result) instanceof AltResult) &&
            (((AltResult)r).ex instanceof CancellationException);
    }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值