openTSDB源码详解之Deferred类简单示例2

版权声明:如若转载,请联系作者。 https://blog.csdn.net/liu16659/article/details/84025905

openTSDB源码详解之Deferred类简单示例2

1.示例2

1.1 代码

程序代码如下:

public static void test2() {
		try {
		    //注意这个时候由 dfd -> dfd List(lstDfd)。但是其类型仍然没变,为String
			List<Deferred<String>> lstDfd = new ArrayList<Deferred<String>>();

			//同时定义一个 cb -> cb list (lstCb)
			List<Callback<String, String>> lstCb = new ArrayList<Callback<String, String>>();

			//使用for循环,将生成的Deferred对象和MyCallback对象分别放入到对应的list 中
            //生成不同的dfd对象 和cb 对象;并将cb 放到 dfd对象中
			for (int i = 1; i <= 10; i++){
				Callback<String, String> cb = new MyCallback();
				Deferred<String> dfd = new Deferred<String>();

				//添加cb
				dfd.addCallback(cb);

				lstDfd.add(dfd);
				lstCb.add(cb);//为什么还把这个cb放到lstCb中?
			}


			//combine stuff
            //注意,此时的Deferred 中的泛型已经是ArrayList<String>
            //这个dfdGroup 的作用是什么? => 为lstDfd中的每一个dfd添加了两个相同的Callback 对象cb
            //一个作为正常的callback,一个作为errorback
            //所以添加之后,last_callback的值就由 2 -> 4
            //整个执行过程如下:
            //01.传入的参数是一个Collection,即lstDfd,从而得到的deferreds.size() = 10
            //02.我觉得parent 应该是 这一步骤 才生成。
            //03.的确如此,groupInOrder(lstDfd)最后会生成一个parent,并赋值给dfdGroup
            //04.而后,会将这个dfdGroup追加一个Callback——cbGroup
            //05.这个parent最后会在lstDfd被调用完自后调用
			Deferred<ArrayList<String>> dfdGroup = Deferred.groupInOrder(lstDfd);

            //创建一个cbGroup引用 指向新的MyGroupCallback对象
            //注意这里使用的是不同的Callback,上面使用的是MyCallback,下面会使用的是MyGroupCallback
            Callback<ArrayList<String>, ArrayList<String>> cbGroup = new MyGroupCallback();

            //给dfdGroup这个Deferred对象添加一个cbGroup的Callback
			dfdGroup.addCallback(cbGroup);

			for (int i = lstDfd.size() - 1; i >= 0; i--){
				lstDfd.get(i).callback(String.valueOf(i + 1));
			}

			//很好奇这个group callback是怎么输出的? => 这个输出是在MyGroupCallback类中的call()方法中。
            //call()[nested class NotifyOrdered in DeferredGroup ]  -> recordCompletion()[DeferredGroup]
            // -> done()[DeferredGroup] -> callback()[Deferred]
            // -> runCallback()[Deferred]  -> doCall()[Deferred] -> call()[Callback实现类MyGroupCallback]
            //怎么触发 dfdGroup的调用? 也就是说,什么时候/什么条件触发了dfdGroup的运行?
            //触发过程如下:
		} catch (Exception e) {}
	}
1.2 分析如下
/**
   * Constructor.
   * @param deferreds All the {@link Deferred}s we want to group.
   * @param ordered If true, the results will be presented in the same order
   * as the {@link Deferred}s are in the {@code deferreds} argument.
   * If false, results will be presented in the order in which they arrive.
   * In other words, assuming that {@code deferreds} is a list of three
   * {@link Deferred} objects {@code [A, B, C]}, then if {@code ordered} is
   * true, {@code results} will be {@code [result A, result B, result C]}
   * whereas if {@code ordered} is false then the order in {@code results}
   * is determined by the order in which callbacks fire on A, B, and C.
   */
  public DeferredGroup(final Collection<Deferred<T>> deferreds,
                       final boolean ordered) {
    nresults = deferreds.size();
    results = new ArrayList<Object>(nresults);

    if (nresults == 0) {
      parent.callback(results);
      return;
    }

    // Callback used to collect results in the order in which they appear.
    final class Notify<T> implements Callback<T, T> {
      public T call(final T arg) {
        recordCompletion(arg);
        return arg;
      }
      public String toString() {
        return "notify DeferredGroup@" + DeferredGroup.super.hashCode();
      }
    };

    // Callback that preserves the original orders of the Deferreds.
    final class NotifyOrdered<T> implements Callback<T, T> {
      private final int index;
      NotifyOrdered(int index) {
        this.index = index;
      }
      public T call(final T arg) {
        recordCompletion(arg, index);
        return arg;
      }
      public String toString() {
        return "notify #" + index + " DeferredGroup@"
          + DeferredGroup.super.hashCode();
      }
    };

    if (ordered) {
      int i = 0;
      for (final Deferred<T> d : deferreds) {
        results.add(null);  // ensures results.set(i, result) is valid.
        // Note: it's important to add the callback after the line above,
        // as the callback can fire at any time once it's been added, and
        // if it fires before results.set(i, result) is valid, we'll get
        // an IndexOutOfBoundsException.
        d.addBoth(new NotifyOrdered<T>(i++));
      }
    } else {
      final Notify<T> notify = new Notify<T>();
      for (final Deferred<T> d : deferreds) {
        d.addBoth(notify);
      }
    }
  }

因为传入的参数 Collection<Deferred<T>> deferreds,
在这里插入图片描述这里的deferreds就是 Deferred<ArrayList<String>> dfdGroup = Deferred.groupInOrder(lstDfd);中的lstDfd。因为在for循环中循环了10次,所以此大小为10。那么得到的nresults=10 ,接着new一个list。results = new ArrayList<Object>(nresults); (笔者注:为何需要new一个list 呢?) 接着到了判断语句:if (ordered){...},这个 ordered变量其实是用于判断到底该怎么输出。

 * @param ordered If true, the results will be presented in the same order
   * as the {@link Deferred}s are in the {@code deferreds} argument.
   * If false, results will be presented in the order in which they arrive.
   * In other words, assuming that {@code deferreds} is a list of three
   * {@link Deferred} objects {@code [A, B, C]}, then if {@code ordered} is
   * true, {@code results} will be {@code [result A, result B, result C]}
   * whereas if {@code ordered} is false then the order in {@code results}
   * is determined by the order in which callbacks fire on A, B, and C.

如果 ordered为true,那么展示结果与在参数 deferredsDeferreds 对象的顺序相同;如果为false,结果将会按照它们到达的顺序去展示。

/**
   * All the results for each Deferred we're grouping.
   * Need to acquires this' monitor before changing.
   * Each result is either of type T, or an Exception.
   */
  private final ArrayList<Object> results;

我们对每个 Deferred对象分组的所有结果。
在改变之前,需要更换这个监视器
每个结果的类型要么是T,要么是一个异常。

 for (final Deferred<T> d : deferreds) {
        results.add(null);  // ensures results.set(i, result) is valid.
        // Note: it's important to add the callback after the line above,
        // as the callback can fire at any time once it's been added, and
        // if it fires before results.set(i, result) is valid, we'll get
        // an IndexOutOfBoundsException.
        d.addBoth(new NotifyOrdered<T>(i++));
      }

对于上述的代码我是不大理解,为什么这里需要将 null添加到 results中?同时最后还有一个addBoth(new NotifyOrdered<T>(i++))操作。而这里的NotifyOrdered就是一个实现了Callback 接口的内部类。
其中的变量i初始值为0,进行自加操作。这个变量i 与后面的int index有关系,作为一个构造参数传入到了 NotifyOrdered()中。

    // Callback that preserves the original orders of the Deferreds.
    final class NotifyOrdered<T> implements Callback<T, T> {
      private final int index;
      NotifyOrdered(int index) {
        this.index = index;
      }
      public T call(final T arg) {
        recordCompletion(arg, index);
        return arg;
      }
      public String toString() {
        return "notify #" + index + " DeferredGroup@"
          + DeferredGroup.super.hashCode();
      }
    };

NotifyOrdered 是一个保留了 Deferreds 对象的原始顺序的Callback
而这里的addBoth()方法如下:

  /**
   * Registers a callback both as a callback and as an "errback".
   * <p>
   * If the deferred result is already available, the callback is executed
   * immediately from this thread (regardless of whether or not the current
   * result is an exception).
   * If the deferred result is not available, this callback is queued and will
   * be invoked from whichever thread gives this deferred its initial result
   * by calling {@link #callback}.
   * @param cb The callback to register.
   * @return {@code this} with an "updated" type.
   */
  public <R> Deferred<R> addBoth(final Callback<R, T> cb) {
    return addCallbacks(cb, cb);
  }

可以看到这里的addBoth()方法其实就是添加两个相同的cb,一个作为正常的callback,一个作为errorback。其addCallbacks(cb,cb) 方法与示例1相同,这里不再叙述。

  /**
   * Returns the parent {@link Deferred} of the group.
   */
  public Deferred<ArrayList<T>> getDeferred() {
    return parent;
  }

返回组中Deferred对象的父亲。
在这里插入图片描述发现这个parent 其实是有值的。

  /**
   * The Deferred we'll callback when all Deferreds in the group have been called back.
   * 我们即将回调的Deferred对象,当组内的所有的Deferreds已经回调完成时。
   */
  private final Deferred<ArrayList<T>> parent = new Deferred<ArrayList<T>>();
  /**
   * Called back when one of the {@link Deferred} in the group completes.
   * 当组内的Deferred对象完成时调用

   * @param result The result of the deferred. deferred对象的值
   * @param index The index of the result.值的索引
   */
  private void recordCompletion(final Object result, final int index) {
    int left;
    synchronized (this) {
      results.set(index, result);
      left = --nresults;
    }
    if (left == 0) {
      done();
    }
  }

result.set(index,result)是用来更新值的。set()方法如下,但是最为关键的是需要理解这个index这个值是怎么变化,其实这个值是随着每个deferred对象而变化的,在构造的时候,就设定了不同的index值,所以会有index在变化的“假象”。这里给出一个变化时的案例
在这里插入图片描述
results中的值为
在这里插入图片描述

    /**
     * Replaces the element at the specified position in this list with
     * the specified element.
     * 使用指定值更新该list指定位置的元素

     * @param index index of the element to replace  
     * 被替代元素的下标
     * 
     * @param element element to be stored at the specified position  
     * 需要存在指定位置的元素值
     * 
     * @return the element previously at the specified position  
     * 返回之前指定位置的元素
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public E set(int index, E element) {
        rangeCheck(index);

        E oldValue = elementData(index);
        elementData[index] = element;
        return oldValue;
    }

其中if (left == 0)的逻辑就是用来判断是否需要开始排序了。done()方法如下:

/** Called once we have obtained all the results of this group. 
    一旦我们获取了这个组内的所有值时,调用done()方法。

    01.这个逻辑控制使用的方法是if(left == 0)。表示组内还有多少个deferred对象没有完成
 */

  private void done() {
    // From this point on, we no longer need to synchronize in order to
    // access `results' since we know we're done, so no other thread is
    // going to call recordCompletion() again.
    for (final Object r : results) {
      if (r instanceof Exception) {
        parent.callback(new DeferredGroupException(results, (Exception) r));
        return;
      }
    }
    parent.callback(results);
  }

if (r instanceof Exception) {...}是用于检查是否为一个异常,如果为一个异常,则直接调用 errorback,我们这里不是errorback,所以这里不会调用errorback,而是调用 callback(results)函数。
在这里插入图片描述
现在我们来观察一下parent值的变化
在这里插入图片描述在这里插入图片描述
实例化之后的值是
在这里插入图片描述
发现值已经变化了,Deferred@1156060786(state=PENDING, result=null, callback=SimpleDeferExample.MyGroupCallback@6956de9, errback=passthrough)
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/liu16659/article/details/84025905