guava concurrent学习(一):AbstractFuture

一、内部类分析

1、Waiter用于将多个等待的线程串起来,内部有成员变量thread与next,组成等待此future完成的链表,最重要的方法是unpark如下:

void unpark() { // releaseWaiters方法会调用这里。
      // This is racy with removeWaiter. The consequence of the race is that we may spuriously call
      // unpark even though the thread has already removed itself from the list. But even if we did
      // use a CAS, that race would still exist (it would just be ever so slightly smaller).
      // 这与removeWaiter之间存在竞争。 竞争的结果可能存在这种情况:即使线程已从列表中删除,我们也可能虚假地调用unpark。
      // 但即使我们确实使用了CAS,这种竞争仍然会存在(它会稍微小一些)。
      Thread w = thread;
      if (w != null) {
        thread = null;
        LockSupport.unpark(w); // get方法里有LockSupport.park操作。
      }
    }
  }

既然这里有LockSupport.unpark,那么必定有某处在调用LockSupport.park,而调用的地方就在get()以及get(long timeout, TimeUnit unit)方法里,这跟jdk里的future是一样的,当主动调用get方法去获取future的结果时,是同步的调用,可能会阻塞线程。

2、Listener用于表示此future添加的监听器,是通过ListenableFuture.addListener添加的,内部有成员变量task、executor以及next,表示在此future完成后,使用executor来执行task。

3、Failure用于表示失败,这是AbstractFuture中的value的6种可能的值之一。

4、Cancellation表示此future取消了,这是AbstractFuture中的value的6种可能的值之一,它内部定义了两个此类型的静态常量,一个表示存在中断取消,另一个表示没有中断取消。

5、SetFuture表示结果取自别的future的结果,这是AbstractFuture中的value的6种可能的值之一。当此future(记为A)的结果是SetFuture的实例时,此实例也会添加到产生结果的future(记为B)的监听器链里,这样的效果是:当B完成时,就会调用B的监听器链上的SetFuture实例来运行,SetFuture实现了Runnable接口,其run方法如下:

public void run() {
      if (owner.value != this) { // 目的是为了判断future是否取消了,complete有类似的判断逻辑。
        // nothing to do, we must have been cancelled, don't bother inspecting the future.
        return;
      }
      Object valueToSet = getFutureValue(future);
      if (ATOMIC_HELPER.casValue(owner, this, valueToSet)) { // 注意这个是casValue,如果owner.value等于this,则将其值设置为valueToSet.
        // 这里体现了SetFuture类名的含义,是来设置future的,而AbstractFuture中的值是用value表示的,所以这里就是设置为getFutureValue的返回值。
        complete(owner);
      }
    }

这个SetFuture实例的run方法运行后,就会设置A的结果,这样A上的监听器链也可以运行起来了。(这个run方法其实并没有再调用了,分析见后面的complete的分析。)

6、AtomicHelper,用于通过CAS方式原子地更新变量,而不是通过加锁的方式来安全地更新变量,它有三个实现类:UnsafeAtomicHelper、SafeAtomicHelper、SynchronizedHelper,在初始化时,如果使用UnsafeAtomicHelper失败了,则使用SafeAtomicHelper,如果还是失败,则使用SynchronizedHelper。前两种因为都使用反射来使改变量的,在一些情况下会失败,所有作者又给出了第三种,失败原因如下:

// Some Android 5.0.x Samsung devices have bugs in JDK reflection APIs that cause
// getDeclaredField to throw a NoSuchFieldException when the field is definitely there.
// For these users fallback to a suboptimal implementation, based on synchronized. This will
// be a definite performance hit to those users.
// 一些Android 5.0.x三星设备在JDK反射API中存在错误,导致getDeclaredField在字段肯定存在时抛出NoSuchFieldException。
// 对于这些用户,基于synchronized,回退到次优实现。 这将对这些用户产生明显的性能影响。
// 见InterruptibleTask里的注释(那里用AtomicReference来实现了)。

二、类变量分析

1、SPIN_THRESHOLD_NANOS=1000L,如果线程的睡眠等待时间小于此值,则使用cpu自旋等待来代替线程睡眠。

2、ATOMIC_HELPER,用于通过CAS原子地修改此future的成员变量以及waiters里的成员变量。

三、成员变量分析

1、value,表示此future的值,有6种情况:

/**
   * This field encodes the current state of the future.
   *
   * 

The valid values are: * *

    *
  • {@code null} initial state, nothing has happened. *
  • {@link Cancellation} terminal state, {@code cancel} was called. *
  • {@link Failure} terminal state, {@code setException} was called. *
  • {@link SetFuture} intermediate state, {@code setFuture} was called. *
  • {@link #NULL} terminal state, {@code set(null)} was called. *
  • Any other non-null value, terminal state, {@code set} was called with a non-null * argument. *
*/

2、listeners,表示此future上的监听器链,内部通过next变量将多个监听器串起来。

3、waiters,表示此future上的等待线程,内部通过next变量将多个等待的线程串起来。三、

四、重要方法分析

1、两个get方法

/**
   * {@inheritDoc}
   *
   * 

The default {@link AbstractFuture} implementation throws {@code InterruptedException} if the * current thread is interrupted during the call, even if the value is already available. * AbstractFuture的默认实现中如果当前线程被中断了则抛出InterruptedException,即使当前已经得到value了,也会抛出InterruptedException。 * * @throws CancellationException {@inheritDoc} */ @CanIgnoreReturnValue @Override public V get(long timeout, TimeUnit unit) throws InterruptedException, TimeoutException, ExecutionException { // NOTE: if timeout < 0, remainingNanos will be < 0 and we will fall into the while(true) loop // at the bottom and throw a timeoutexception. // 注意:如果timeout <0,remainingNanos将<0,我们将进入底部的while(true)循环并抛出timeoutexception。 // 如果remainingNanos<0,则这里的实现中,会直接到最下面的if(isDone())那里,将会抛出超时异常。这里的while(true)应该是在形容这样的效果:总是会抛出超时异常,而非实现中有while(true)。 // 感觉作者的注释不是太详细、恰当。 long remainingNanos = unit.toNanos(timeout); // we rely on the implicit null check on unit. if (Thread.interrupted()) { throw new InterruptedException(); } Object localValue = value; if (localValue != null & !(localValue instanceof SetFuture)) { return getDoneValue(localValue); } // we delay calling nanoTime until we know we will need to either park or spin // 我们推迟调用nanoTime,直到我们知道我们需要停放或旋转 final long endNanos = remainingNanos > 0 ? System.nanoTime() + remainingNanos : 0; long_wait_loop: if (remainingNanos >= SPIN_THRESHOLD_NANOS) { Waiter oldHead = waiters; if (oldHead != Waiter.TOMBSTONE) { Waiter node = new Waiter(); // 这里想要使用park操作,所以创建了一个Waiter,见get方法上的注释: // * Don't create Waiter nodes if you aren't going to park, this helps reduce contention on the // waiters field. // 注意:Waiter()里的实现并不是空的(不要有主观上的想法),其实现是把当前线程放入node.thread。 // 注意:执行get的线程是当前线程,而执行Waiter.unpark里的线程是执行AbstractFuture的线程。 // 所以效果就是AbstractFuture的线程去执行任务,然后其他线程来取数据时可能会被阻塞住以等待任务执行完成或者超时返回。 do { node.setNext(oldHead); if (ATOMIC_HELPER.casWaiters(this, oldHead, node)) { while (true) { LockSupport.parkNanos(this, remainingNanos); // 这个是阻塞在this这个对象上,parkNanos内部会有当前线程,见其实现。 // Check interruption first, if we woke up due to interruption we need to honor that. if (Thread.interrupted()) { // 对Thread.interrupt()方法很详细的介绍:https://blog.csdn.net/yonghumingshishenme/article/details/6285259 // 理解java线程的中断(interrupt):https://blog.csdn.net/canot/article/details/51087772 // https://www.cnblogs.com/bingscode/p/6211837.html:https://www.cnblogs.com/bingscode/p/6211837.html removeWaiter(node); // park操作已结束,所以移除这个node。 throw new InterruptedException(); } // parkNanos的注释里说了很多种可能的唤醒原因。 // Otherwise re-read and check doneness. If we loop then it must have been a spurious // wakeup localValue = value; if (localValue != null & !(localValue instanceof SetFuture)) { return getDoneValue(localValue); } // timed out? remainingNanos = endNanos - System.nanoTime(); if (remainingNanos < SPIN_THRESHOLD_NANOS) { // Remove the waiter, one way or another we are done parking this thread. removeWaiter(node); break long_wait_loop; // jump down to the busy wait loop } // 继续阻塞等待 } } oldHead = waiters; // re-read and loop. } while (oldHead != Waiter.TOMBSTONE); // 不断地尝试cas。 } // re-read value, if we get here then we must have observed a TOMBSTONE while trying to add a // waiter. // 见get方法上面的注释: // * Future completion can be observed if the waiters field contains a TOMBSTONE return getDoneValue(value); } // If we get here then we have remainingNanos < SPIN_THRESHOLD_NANOS and there is no node on the // waiters list // 到这里时,remainingNanos < SPIN_THRESHOLD_NANOS,并用waiters链表里没有node. // 对于这个没有node,可以这样理解,增加一个node就是为了调用park方法,如果有多个node,则后一个node会park,然后等待它前面的node的unpark,最后再upnark自己。 // 所以,到这里只,waiters链表里是没有node的,要不然,还是在park的状态,即阻塞的状态。(注意,上面的循环中有removeWaiter的操作,所以到这里时是没有node的。) while (remainingNanos > 0) { localValue = value; if (localValue != null & !(localValue instanceof SetFuture)) { return getDoneValue(localValue); } if (Thread.interrupted()) { throw new InterruptedException(); } remainingNanos = endNanos - System.nanoTime(); // 继续自旋等待 } String futureToString = toString(); // It's confusing to see a completed future in a timeout message; if isDone() returns false, // then we know it must have given a pending toString value earlier. If not, then the future // completed after the timeout expired, and the message might be success. // 在超时消息中看到Future的完成会令人产生困惑; 如果isDone()返回false,那么我们知道它必须先提供一个在等待期间的toString值。 // 如果isDone()返回true,那么Future在超时到期时完成,并且返回的消息提示是成功的。 if (isDone()) { // 这个其实就是想在超时再检查一次看完成没有。 throw new TimeoutException( "Waited " + timeout + " " + unit.toString().toLowerCase(Locale.ROOT) + " but future completed as timeout expired"); } throw new TimeoutException( // 超时了,没有完成 "Waited " + timeout + " " + unit.toString().toLowerCase(Locale.ROOT) + " for " + futureToString); } /** * {@inheritDoc} * *

The default {@link AbstractFuture} implementation throws {@code InterruptedException} if the * current thread is interrupted during the call, even if the value is already available. * AbstractFuture的默认实现中如果当前线程被中断了则抛出InterruptedException,即使当前已经得到value了,也会抛出InterruptedException。 * * @throws CancellationException {@inheritDoc} */ @CanIgnoreReturnValue @Override public V get() throws InterruptedException, ExecutionException { // get方法是获取future的结果,可能需要调用park操作阻塞获取线程, // 所以可能会增加Waiter。 // 而Listener则是添加一个新的监听任务,等到future完成后自动执行。 if (Thread.interrupted()) { throw new InterruptedException(); } Object localValue = value; if (localValue != null & !(localValue instanceof SetFuture)) { return getDoneValue(localValue); } Waiter oldHead = waiters; if (oldHead != Waiter.TOMBSTONE) { Waiter node = new Waiter(); do { node.setNext(oldHead); if (ATOMIC_HELPER.casWaiters(this, oldHead, node)) { // we are on the stack, now wait for completion. while (true) { LockSupport.park(this); // releaseWaiters里会最终调用LockSupport.unpark // Check interruption first, if we woke up due to interruption we need to honor that. if (Thread.interrupted()) { removeWaiter(node); throw new InterruptedException(); } // Otherwise re-read and check doneness. If we loop then it must have been a spurious // wakeup localValue = value; if (localValue != null & !(localValue instanceof SetFuture)) { return getDoneValue(localValue); } } } oldHead = waiters; // re-read and loop. } while (oldHead != Waiter.TOMBSTONE); } // re-read value, if we get here then we must have observed a TOMBSTONE while trying to add a // waiter. return getDoneValue(value); }

2、removeWaiter方法:

private void removeWaiter(Waiter node) { // 这里的实现是一个正常的删除链表中某元素的操作。
    node.thread = null; // mark as 'deleted'
    restart:
    while (true) {
      Waiter pred = null; // 前驱节点,一开始头节点的前驱节点为null。
      Waiter curr = waiters; // 当前节点
      if (curr == Waiter.TOMBSTONE) {
        return; // give up if someone is calling complete
      }
      Waiter succ; // 后继节点
      while (curr != null) {
        succ = curr.next;
        if (curr.thread != null) { // we aren't unlinking this node, update pred.
          pred = curr;
        } else if (pred != null) { // We are unlinking this node and it has a predecessor.
          pred.next = succ;
          if (pred.thread == null) { // We raced with another node that unlinked pred. Restart. 注意:这些thread、next都是volatile类型的。
            // 为什么只在这里检查一下可能存在的竞争而导致pred.thread为null呢?原因是这样的:因为pred.next=succ之后,就假设pred之前的元素都是有效的、非删除状态了,
            // 所以在这里要把一下关,再检查一下当前的节点是否为有效的。
            // 其实这里再次判断只是为了能在删除无效节点这点上更加有效率而已,而非必须要这样做的,其实这里不检测,也不会有并发问题。
            continue restart;
          }
        } else if (!ATOMIC_HELPER.casWaiters(this, curr, succ)) { // We are unlinking head
          continue restart; // We raced with an add or complete 这个竞争情况考虑的太严谨了
        }
        curr = succ;
      }
      break;
    }
  }

3、getFutureValue

/**
   * Returns a value that satisfies the contract of the {@link #value} field based on the state of
   * given future.
   * 根据给定的future的状态返回一个满足{@link #value}字段的约定(value字段有多种可能的情况,见其注释)的值。
   *
   * 

This is approximately the inverse of {@link #getDoneValue(Object)} * 这与{@link #getDoneValue(Object)}大致相反。 * * getFutureValue是从给定的future中得到其结果对象,这个对象有多种可能的值,见value上面的注释。 * 而getDoneValue同是从getFutureValue得到的对象中再解析出特定的结果,比如具体类型的值、抛出特定的异常等等。 * * getDoneValue多是给外部线程获取最终结果用的,而getFutureValue的使用场景是在类内部获取给定的输入future的结果,以便用这个结果来设置此future的结果。 * * 注意区别getFutureValue与SetFuture的不同,getFutureValue是在给定的future完成时取结果用的,而SetFuture是在给定的future没完成时临时当作此future的value结果使用的 */ private static Object getFutureValue(ListenableFuture future) { Object valueToSet; if (future instanceof TrustedFuture) { // Break encapsulation for TrustedFuture instances since we know that subclasses cannot // override .get() (since it is final) and therefore this is equivalent to calling .get() // and unpacking the exceptions like we do below (just much faster because it is a single // field read instead of a read, several branches and possibly creating exceptions). // 打破TrustedFuture实例的封装,因为我们知道子类不能覆盖.get()(因为它是final),因此这相当于调用.get()并像下面那样解压缩异常 // (因为它是单个字段读取而不是读取几个分支并且是可能产生异常的几个分支,所以更快)。 Object v = ((AbstractFuture) future).value; if (v instanceof Cancellation) { // If the other future was interrupted, clear the interrupted bit while preserving the cause // this will make it consistent with how non-trusted futures work which cannot propagate the // wasInterrupted bit // 如果另一个future被中断,在保留原因的同时清除被中断的位,这将使其与不可信的future的工作方式一致,即不传播isInterrupted位。 // 这里清除了中断位,由外部调用者根据cause去检测是否为中断异常,然后可以根据需要再次抛出异常。 // 这个不可信的future是指,不能保证外部的所有future都会传播这个中断位,所以只能放宽约定,不要依赖这个中断位的传递情况,只传递原因。 // 这个见setFuture方法前的注释。 Cancellation c = (Cancellation) v; if (c.wasInterrupted) { v = c.cause != null ? new Cancellation(/* wasInterrupted= */ false, c.cause) : Cancellation.CAUSELESS_CANCELLED; } } return v; } else { // Otherwise calculate valueToSet by calling .get() try { Object v = getDone(future); // 这个是Futures里的方法,在具体实现中是先检查是否已完成的,是不会阻塞线程的。 valueToSet = v == null ? NULL : v; } catch (ExecutionException exception) { // 这些异常,见getDone里的方法注释。 valueToSet = new Failure(exception.getCause()); } catch (CancellationException cancellation) { valueToSet = new Cancellation(false, cancellation); } catch (Throwable t) { valueToSet = new Failure(t); } } return valueToSet; }

4、getDoneValue

/** Unboxes {@code obj}. Assumes that obj is not {@code null} or a {@link SetFuture}. */
  // 这个方法主要是在get方法里被调用,在调用这个方法之前会判断obj不为null,且不是SetFuture.
  // getDoneValue与getFutureValue的不同之处,参考getFutureValue里的注释。
  private V getDoneValue(Object obj) throws ExecutionException {
    // While this seems like it might be too branch-y, simple benchmarking proves it to be
    // unmeasurable (comparing done AbstractFutures with immediateFuture)
    if (obj instanceof Cancellation) {
      throw cancellationExceptionWithCause("Task was cancelled.", ((Cancellation) obj).cause);
    } else if (obj instanceof Failure) {
      throw new ExecutionException(((Failure) obj).exception);
    } else if (obj == NULL) {
      return null;
    } else {
      @SuppressWarnings("unchecked") // this is the only other option
      V asV = (V) obj;
      return asV;
    }
  }

5、cancel

/**
   * {@inheritDoc}
   *
   * 

If a cancellation attempt succeeds on a {@code Future} that had previously been {@linkplain * #setFuture set asynchronously}, then the cancellation will also be propagated to the delegate * {@code Future} that was supplied in the {@code setFuture} call. * * 如果此future取消了,则也会将取消传播到代理future,这个代理future是通过setFuture设置的。(见setFuture方法的注释) * *

Rather than override this method to perform additional cancellation work or cleanup, * subclasses should override {@link #afterDone}, consulting {@link #isCancelled} and {@link * #wasInterrupted} as necessary. This ensures that the work is done even if the future is * cancelled without a call to {@code cancel}, such as by calling {@code * setFuture(cancelledFuture)}. * 不要覆盖此方法来执行其他取消工作或清理, 子类应覆盖{@link #afterDone},根据需要咨询{@link #isCancelled}和{@link #wasInterrupted}。 * 这确保即使在未调用{@code cancel}的情况下取消future也可以完成工作,例如通过调用{@code setFuture(cancelledFuture)}。 */ @CanIgnoreReturnValue @Override public boolean cancel(boolean mayInterruptIfRunning) { Object localValue = value; boolean rValue = false; if (localValue == null | localValue instanceof SetFuture) { // 注意:这是一个位运算,两个都会判断 // Try to delay allocating the exception. At this point we may still lose the CAS, but it is // certainly less likely. Object valueToSet = GENERATE_CANCELLATION_CAUSES ? new Cancellation( mayInterruptIfRunning, new CancellationException("Future.cancel() was called.")) : (mayInterruptIfRunning ? Cancellation.CAUSELESS_INTERRUPTED : Cancellation.CAUSELESS_CANCELLED); AbstractFuture abstractFuture = this; while (true) { if (ATOMIC_HELPER.casValue(abstractFuture, localValue, valueToSet)) { rValue = true; // 这个指示取消操作是否执行成功了。如果在执行取消时future已经完成了,则执行取消操作失败。 // We call interuptTask before calling complete(), which is consistent with // FutureTask if (mayInterruptIfRunning) { abstractFuture.interruptTask(); } complete(abstractFuture); if (localValue instanceof SetFuture) { // propagate cancellation to the future set in setFuture, this is racy, and we don't // care if we are successful or not. // 传播cancellation,可能存在竞争,但是不管是否成功 ListenableFuture futureToPropagateTo = ((SetFuture) localValue).future; if (futureToPropagateTo instanceof TrustedFuture) { // If the future is a TrustedFuture then we specifically avoid calling cancel() // this has 2 benefits // 1. for long chains of futures strung together with setFuture we consume less stack // 2. we avoid allocating Cancellation objects at every level of the cancellation // chain // We can only do this for TrustedFuture, because TrustedFuture.cancel is final and // does nothing but delegate to this method. /** * 如果Future是TrustedFuture,那么我们特别避免调用cancel() * *   这有两个好处 *   1.对于通过setFuture串起来的长的future链,我们消耗的堆栈更少 *   2.我们避免在取消链的每个级别分配取消对象。 * * 我们只能为TrustedFuture执行此操作,因为TrustedFuture.cancel是final,除了委托此方法之外什么都不做。 */ AbstractFuture trusted = (AbstractFuture) futureToPropagateTo; localValue = trusted.value; if (localValue == null | localValue instanceof SetFuture) { abstractFuture = trusted; continue; // loop back up and try to complete the new future // 这也算是一个非递归的写法,只不过这个setFuture的委托链是单一的一条链, // 不像listener一样是像二叉树一样的东西。见complete里的注释。 } } else { // not a TrustedFuture, call cancel directly. futureToPropagateTo.cancel(mayInterruptIfRunning); // 注意,这个是方法调用,目前还在while循环里。 } } break; } // obj changed, reread localValue = abstractFuture.value; // 更新localValue。 if (!(localValue instanceof SetFuture)) { // obj cannot be null at this point, because value can only change from null to non-null. // So if value changed (and it did since we lost the CAS), then it cannot be null and // since it isn't a SetFuture, then the future must be done and we should exit the loop // 此时obj不能为null,因为value只能从null更改为非null。 因此,如果值发生了变化(并且自从我们丢失了CAS之后就发生了变化),那么它不能为空, // 并且因为它不是SetFuture,那么必定是完成future了,我们应该退出循环 break; } } } return rValue; }

6、addListener方法比较简单,如果此future还没有完成,则添加到监听器链里,如果future已经完成了,则直接执行此监听器。

7、set(V value)与setException(Throwable throwable)方法比较简单,都是设置最终结果,设置成功后,就执行complete方法了。

8、setFuture方法,比较复杂,在将此future的结果设置为SetFuture实例的同时,也会将此实例添加到取结果的future的监听器链上。

/**
   * Sets the result of this {@code Future} to match the supplied input {@code Future} once the
   * supplied {@code Future} is done, unless this {@code Future} has already been cancelled or set
   * (including "set asynchronously," defined below).
   *
   * 一旦提供的{@code Future}完成,设置此{@code Future}的结果以匹配提供的输入{@code Future},
   * 除非此{@code Future}已被取消或设置(包括“异步设置, “定义如下)。
   *
   * 

If the supplied future is {@linkplain #isDone done} when this method is called and the call * is accepted, then this future is guaranteed to have been completed with the supplied future by * the time this method returns. If the supplied future is not done and the call is accepted, then * the future will be set asynchronously. Note that such a result, though not yet known, * cannot be overridden by a call to a {@code set*} method, only by a call to {@link #cancel}. * *

如果在调用此方法并且接受调用时提供的future是{@linkplain #isDone done},那么在此方法返回时, * 将保证使用提供的future完成此future。 如果提供的future没有完成且此调用已被授受,则future将被异步设置。 * 请注意,结果目前还不确定,不能通过调用{@code set *}方法来覆盖这样的结果,只能通过调用{@link #cancel}来设置。 * *

If the call {@code setFuture(delegate)} is accepted and this {@code Future} is later * cancelled, cancellation will be propagated to {@code delegate}. Additionally, any call to * {@code setFuture} after any cancellation will propagate cancellation to the supplied {@code * Future}. * *

如果{@code setFuture(delegate)}调用被接受了,并且稍后取消此{@code Future},则取消将传播到{@code delegate}。 * 此外,任何取消操作后的任何{@code setFuture}调用都会将取消传播到所提供的{@code Future}。(这个的实现见setFuturn方法的最后面, * 这里的传播时指要设置时发现已被取消,就直接传播到参数future,而cancel方法里的传播动作则是在setFuture后引起的传播。) * *

Note that, even if the supplied future is cancelled and it causes this future to complete, * it will never trigger interruption behavior. In particular, it will not cause this future to * invoke the {@link #interruptTask} method, and the {@link #wasInterrupted} method will not * return {@code true}. * *

请注意,即使提供的future被取消并且导致此future完成,也不会触发中断行为。 * 特别是,它不会导致此future调用{@link #interruptTask}方法,并且{@link #wasInterrupted}方法将不会返回{@code true}。 * (这个见SetFuture.run() -> getFutureValue方法里的实现。) * * @param future the future to delegate to (就是让this这个future去代理参数future,即从参数future中取得this这个future的最终执行结果。 * @return true if the attempt was accepted, indicating that the {@code Future} was not previously * cancelled or set. * @since 19.0 */ @Beta @CanIgnoreReturnValue protected boolean setFuture(ListenableFuture future) { checkNotNull(future); Object localValue = value; if (localValue == null) { if (future.isDone()) { Object value = getFutureValue(future); if (ATOMIC_HELPER.casValue(this, null, value)) { complete(this); return true; } return false; } SetFuture valueToSet = new SetFuture(this, future); if (ATOMIC_HELPER.casValue(this, null, valueToSet)) { // isDone以及get方法里会判断value是否为SetFuture类型的。 // the listener is responsible for calling completeWithFuture, directExecutor is appropriate // since all we are doing is unpacking a completed future which should be fast. // 监听器负责调用completeWithFuture,directExecutor是合适的,因为我们所做的就是解包一个完成的future,这是非常快的操作。 try { future.addListener(valueToSet, directExecutor()); // 这个是MoreExecutors里的方法 // 当future完成时,就会去执行valueToSet(也是一个listener)里的run方法,然后设置this的value值。 // 上面是future主动完成,然后通过this的,如果future取消了,不会导致this的中断方法的调用,见setFuture前面的方法注释。 // 这个在this上调用setFuture后,只能再去调用cancel方法,而不能再次调用set方法,见setFuture前面的方法注释。 // (其实这个SetFuture值,也算是this的一种完成状态,只不过最终的正常结果通知是由future完成后调用listener, // 然后调用SetFuture里的run方法最终完成this的value值的设置。) // 如果this上调用cancel方法,则是this主动了,然后cancel会传播到future上,见setFuture前面的方法注释。 // 更新注释:这个directExecutor()好像没有用了,见SetFuture.run方法的注释以及complete方法里的注释。 // 注意:setFuture时,如果输入future还没有完成, // 则只是将其vauleToSet加入输入future的监听器队列,而不会调用this这个future的complete, // 只有等待输入future完成后,future.complete会通过valueToSet.run设置this这个future的结果(这个过程, // 要看,AbstractFuture.complete里的实现。更新:因为AbstractFuture.complete里检测了SetFuture, // 做非递归处理了,不需要使用valueToSet.run了,但是效果是一样的。) // 然后才会调用this这个future的complete。 // 可以写个例子看看,比如使用FluentFuture.catchingAsync写个例子。 } catch (Throwable t) { // addListener has thrown an exception! SetFuture.run can't throw any exceptions so this // must have been caused by addListener itself. The most likely explanation is a // misconfigured mock. Try to switch to Failure. // addListener抛出异常! SetFuture.run不能抛出任何异常,因此这必须是由addListener本身引起的。 最可能的解释是错误配置的模拟。 尝试切换到失败。 // 如果设置监听器时任务future已完成,则会去直接执行,在直接执行时,会调用SetFuture.run,所以上面会提到这个方法。 // 可以看ListenableFuture.addListener方法的注释,可能会抛出RejectedExecutionException,继承自RuntimeException,是免检异常。 Failure failure; try { failure = new Failure(t); } catch (Throwable oomMostLikely) { failure = Failure.FALLBACK_INSTANCE; } // Note: The only way this CAS could fail is if cancel() has raced with us. That is ok. // 注意:此CAS失败的唯一方法是cancel()与我们竞争。 那没问题。 // 这里只所以说中唯一的可能竞争的方法是cancel,是因为上面已经用cas成功设置value了,所以其他set方法是不可用的,只有cancel可能重写这个value字段。见此方法前的注释。 // 这里只所以失败也没问题是因为:上面要设置addListener,出现了异常,这里要设置出错的异常,而由于cancel的竞争导致设置出错异常失败, // 反正addListener没设置成功同时cancel设置取消了,则效果上没什么问题。 boolean unused = ATOMIC_HELPER.casValue(this, valueToSet, failure); } return true; // 到这里时,value为SetFuture、Cancellation、Failure三者中的一个。 } localValue = value; // we lost the cas, fall through and maybe cancel } // The future has already been set to something. If it is cancellation we should cancel the // incoming future. // 此future(this)已经被设置为某种对象,如果它是Cancellation类型的,则取消将传播到输入的future,见下面的实现,还有此方法前的注释说明。 if (localValue instanceof Cancellation) { // we don't care if it fails, this is best-effort. future.cancel(((Cancellation) localValue).wasInterrupted); } return false; }

9、complete方法,这个方法首先会调用releaseWaiters方法,释放所有阻塞等待结果的线程。这个方法会将监听器链上的所有监听器都反转一下,也就是最先加入的最先执行,然后挨个调用它们,在调用监听器时,判断其是否为SetFuture类型的,如果是的话,继而设置SetFutre的owner future(即等待此future的结果的future)的值,进而处理owner future的监听器链并把此future的未处理完的监听器挂在owner future的监听器链的末尾,其实是个非递归实现,这也就是前面介绍SetFuture中说其run方法没有再使用的原因。具体看代码里的分析:

/** Unblocks all threads and runs all listeners. */
  private static void complete(AbstractFuture future) {
    Listener next = null;
    outer:
    while (true) {
      future.releaseWaiters();
      // We call this before the listeners in order to avoid needing to manage a separate stack data
      // structure for them.
      // afterDone() should be generally fast and only used for cleanup work... but in theory can
      // also be recursive and create StackOverflowErrors
      // 我们在侦听器之前调用它,以避免需要为它们管理单独的堆栈数据结构。
      // afterDone()通常应该很快并且仅用于清理工作......但理论上也可以递归并创建StackOverflowErrors。
      future.afterDone();
      // push the current set of listeners onto next
      next = future.clearListeners(next); // 注意这个next!!!
      future = null;
      while (next != null) {
        Listener curr = next;
        next = next.next; // 注意这个next!!!
        Runnable task = curr.task;
        if (task instanceof SetFuture) { // 具体见setFuture方法里,会将SetFuture封闭为listener加入到监听器链里。
          SetFuture setFuture = (SetFuture) task;
          // We unwind setFuture specifically to avoid StackOverflowErrors in the case of long
          // chains of SetFutures
          // Handling this special case is important because there is no way to pass an executor to
          // setFuture, so a user couldn't break the chain by doing this themselves.  It is also
          // potentially common if someone writes a recursive Futures.transformAsync transformer.
          // 我们特别解开setFuture以避免在SetFutures长链的情况下出现StackOverflowErrors。处理这种特殊情况很重要,
          // 因为无法将executor传递给setFuture,因此用户无法通过自己执行此操作来破坏链。
          // 如果有人编写递归的Futures.transformAsync转换器,这也是很常见的。
          future = setFuture.owner;
          if (future.value == setFuture) { // 目的是为了判断future是否取消了,跟SetFuture.run里的作用一样。
            Object valueToSet = getFutureValue(setFuture.future);
            if (ATOMIC_HELPER.casValue(future, setFuture, valueToSet)) { // 注意这个future,如果这里操作成功,则这个future算是完成了,
              // 然后开始跳到外层去继续处理此future上的waiters以及listener。注意:在处理这个future时,并不会丢弃这个future所属的setFuture所属的listener后面的listener,
              // 因为后面的listener已经存放在next里了,然后在continue outer后,会把next放入此future的listener链表的后面。
              // 这里的奇葩实现其实是非递归写法,如果递归写法会比较好理解,但是效率可能会低一些。
              // 这里listener的形状如同是二叉树一样,比如future1有三个listener,listenerA, listenerB, listenerC,而listenerB里的任务可能是一个SetFuture,
              // 然后这个SetFuture属于future2,那么从future1的listener链表处理到listenerB时,就会去处理listenerB的future2上的listener链表,比如为listenerD,listenerF,
              // 则continue后的总的listener链表为:listenerD, listenerF, listenerC。
              continue outer;
            }
          }
          // other wise the future we were trying to set is already done.
        } else {
          executeListener(task, curr.executor);
        }
      }
      break;
    }
  }

complete方法里也留了一些接口,如afterDone,

10、releaseWaiters方法

/** Releases all threads in the {@link #waiters} list, and clears the list. */
  private void releaseWaiters() {
    Waiter head;
    do {
      head = waiters;
    } while (!ATOMIC_HELPER.casWaiters(this, head, Waiter.TOMBSTONE));// 这个是如果一直不成功,就一直尝试,如何理解呢?
    // 这样子理解:Waiter表示要操作park动作,要阻塞线程,如果当前的线程一直不能成功,则表示一直有新的线程在阻塞等待结果。只有当当前线程操作成功,
    // 成功将waiters设置为Waiter.TOMBSTONE,表示此AbstractFuture已经完成,可以去取value了。见get方法上面的注释。
    for (Waiter currentWaiter = head; currentWaiter != null; currentWaiter = currentWaiter.next) { // 挨个释放Waiter。
      currentWaiter.unpark(); // get方法里有LockSupport.park操作。
    }
  }

四、细节

1、要设置一个好的异步编程框架要考虑哪些问题?

a. 如果获取异步计算的结果;

b. 当多个线程同时发起获取异步计算结果的调用时,如果异步计算还没有完成,则这些线程要阻塞,如何组织这些阻塞的线程;

c. 如何在异步计算完成之后执行已经设计好的回调方法;

d. 当多个多个线程同时设置回调后,如何组织这些回调能使得在异步计算完成后有序地执行这些不同线程上的回调;

e. 异步调用已发起,同时也设置了多个回调,还可能有多个已经阻塞了的线程等待取异步计算的结果,如果此时异步计算出异常、被取消或者人为设置其结果了,则要如何处理这些回调,以及如何唤醒这些已经睡眠的线程。

f. 在异步计算过程中,不同线程可能同时操作一个对象,如何高效地处理竞争、避免阻塞、避免上下文切换同时又不出现并发问题?

g. 异步计算的状态有哪些?

上面是设计一个高效的异步编程框架要考虑的基本问题,对于上面问题,看看guava concurrent中的AbstractFuture是如何给出答案的:

a. AbstractFuture继承自jdk的future,重写了get方法以及带超时功能的get方法,在取数据时,如果异步计算已完成,则直接拿到结果就返回,如果 异步计算还没有完成,则阻塞等待。

b. AbstractFuture内部使用Waiter来实现非阻塞Treiber Stack来组织这些阻塞的线程,《java并发编程实战》第二版15.4.1中有介绍这个算法,在《java并发编程实战》第二版15.4.3节中有说明,使用原子化域主要是为了相对于使用AtomicReference细微的性能提升。

c. 在异步计算任务执行完后,会去设置future的结果,会调用set方法,进而会调用complete,然后会执行已经设置的监听器链。这一套流程的具体实现,可以看看TrustedListenableFutureTask、TrustedFutureInterruptibleTask与InterruptibleTask是如何与AbstractFuture产生关系的。

d. 跟b中的实现类似,使用Listener来实现非阻塞Treiber Stack来组织这些异步回调。

e. 在异步计算的每一步中,都要检测是否已完成、是否已取消以及在出现异步时处理监听器以及唤醒阻塞的线程。

f. 作者了为避免阻塞、避免上下文切换,在处理竞争时,都使用了CAS操作,以及在睡眠时间小于1000L ns 时使用cpu自旋代替睡眠。

g. 在AbstractFuture中,定义了6种future的状态,来处理可能存在的复习情况。

除了上面的一些功能、问题外,AbstractFuture还实现了更有趣的功能,即setFuture方法所做的,从输入future的结果中取得此future的结果,这涉及到如果表示此future的结果状态,以及如果在输入future完成后通知此future或者此future何时去取输入future的结果,还有就是此future与输入future之间如何维持状态上的“同步”,即当此future取消时,是否要取消输入future等等问题。在这里,AbstractFuture使用SetFuture这个类型表示取自其他future的结果,SetFuture又以监听器的身份加入到输入future的监听器链中,这样就实现了当输入future完成后通知此future的功能。

除了AbstractFuture里的外,guava concurrent实现了其他更高级的功能,比如FluentFuture里的要实现流式、链式调用的方法,以及Futures里的聚合future的方法等等。其他的酷炫的功能都是在AbstractFuture提供的基础功能之上实现的。

2、为了更好的学习guava concurrent,我从其中摘出了一些文件与类,组成了一个小工程,方便理解guava concurrent的设计思想,资源见:concurrent,里面有可运行的例子,现结合上面的分析,可以有更深的理解和体会。

你可能感兴趣的:(java,guava,concurrent,AbstractFuture)