OkHttp源码分析(二)-----------------分发器Dispatcher

Dispatcher简介

分发器,又称为调度器,是OkHttp中核心的一个类,维护着所有请求的状态,并且在类中维护一个线程池,用来执行请求,关于其具体使用可参见OkHttp源码分析(一)

Dispatcher成员变量

public final class Dispatcher {
   //最大并发请求数
   private int maxRequests = 64;
   //每个主机最大请求数
   private int maxRequestsPerHost = 5;
   private @Nullable Runnable idleCallback;
   //线程池用来维护执行请求和等待请求 
   private @Nullable ExecutorService executorService;
   //异步的等待队列
   private final Deque<AsyncCall> readyAsyncCalls = new  
     ArrayDeque<>();
   //异步的执行队列
   private final Deque<AsyncCall> runningAsyncCalls = new    
     ArrayDeque<>();
   //同步的执行队列
   private final Deque<RealCall> runningSyncCalls = new  
     ArrayDeque<>();

   ........
}

异步执行时Dispatcher的工作机制

异步执行其实调用的是RealCall#enqueue方法如下所示

@Override public void enqueue(Callback responseCallback) {
    synchronized (this) {
    if (executed) throw new IllegalStateException("Already Executed");
    executed = true;
  }
  captureCallStackTrace();
  eventListener.callStart(this);
  //注意这里调用的dispatcher的enqueue方法
  client.dispatcher().enqueue(new AsyncCall(responseCallback));
}

接着来看Dispatcher#enqueue

synchronized void enqueue(AsyncCall call) {
  //先判断是否超过相应的阈值,即是最大并发请求数,每个主机最大请求数
  if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
    //若是没有超过,添加请求到执行的队列中
    runningAsyncCalls.add(call);
    //使用线程池去执行该请求     ---------------(1)
    executorService().execute(call);
  } else {
    //否则就放到等待的队列中
    readyAsyncCalls.add(call);
  }
}

(1)我们先来看看executorService()方法:

public synchronized ExecutorService executorService() {
 if (executorService == null) {
   //其实就可以看到此方法就是创建一个线程池
   executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
      new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
}
return executorService;
}

上述过程中我们可以看到异步请求的时候是启用线程池去执行任务的,那么现在来具体是怎么执行,我们注意到上述中的executorService().execute(call)方法中传入的参数是AsyncCall类型,那么见RealCall#AsyncCall源码如下:

final class AsyncCall extends NamedRunnable {
  private final Callback responseCallback;

  AsyncCall(Callback responseCallback) {
    super("OkHttp %s", redactedUrl());
    this.responseCallback = responseCallback;
  }

  ......

  //执行任务
  @Override protected void execute() {
    try {
    //中间内容分析详见《OkHttp源码分析(一)》
      ......
      Response response = getResponseWithInterceptorChain();
      ......

    } catch (IOException e) {
      ......  
    } finally {
      //执行完毕之后要销毁请求,回收资源
      client.dispatcher().finished(this);
    }
  }
}

可以看到执行完成之后是一定会执行Dispatcher#finished,所以接下来要做的就是分析一下finished方法源码

/** Used by {@code AsyncCall#run} to signal completion. */
void finished(AsyncCall call) {
  //异步请求结束时调用此方法
  finished(runningAsyncCalls, call, true);
}

/** Used by {@code Call#execute} to signal completion. */
void finished(RealCall call) {
  //同步请求结束时调用此方法
  finished(runningSyncCalls, call, false);
}

private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
  int runningCallsCount;
  Runnable idleCallback;
  synchronized (this) {
    //若是没有异常就直接移除
    if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
    //判断是是否需将Call从等待队列中提升到执行队列中
    if (promoteCalls) promoteCalls();  //-------------(1)
    //获取正在执行中的call,包括同步和异步
    runningCallsCount = runningCallsCount();
    idleCallback = this.idleCallback;
  }

  if (runningCallsCount == 0 && idleCallback != null) {
    idleCallback.run();
  }
}

(1)Dispathcer#promoteCalls方法:

private void promoteCalls() {
  //等待队列runningAsyncCalls已经满了,没有办法添加请求
  if (runningAsyncCalls.size() >= maxRequests) return; 
  //等待队列中没有被等待执行的请求
  if (readyAsyncCalls.isEmpty()) return; 
  //遍历等待队列,获取请求
  for (Iterator<AsyncCall> i = readyAsyncCalls.iterator();   i.hasNext(); ) {
   AsyncCall call = i.next();
   //判断该请求的host是否小于每个host最大请求阈值
   if (runningCallsForHost(call) < maxRequestsPerHost) {
     i.remove();
     //若是没有则将该请求添加到执行队列runningAsyncCalls中,并通过线程池执行该请求
     runningAsyncCalls.add(call);
     executorService().execute(call);
   }
   //同理,若是遍历过程中执行队列数量已满,则终止遍历
   if (runningAsyncCalls.size() >= maxRequests) return; 
 }
}

至此当等待队列readyAsyncCalls中所有的请求执行完成之后return结束。

同步执行时Dispatcher的工作机制

//其中原理和异步执行一样不再详述
@Override public Response execute() throws IOException {
  synchronized (this) {
    if (executed) throw new IllegalStateException("Already Executed");
    executed = true;
  }
  captureCallStackTrace();
  eventListener.callStart(this);
  try {
    //添加请求到Dispatcher中
    client.dispatcher().executed(this);
    Response result = getResponseWithInterceptorChain();
    if (result == null) throw new IOException("Canceled");
    return result;
  } catch (IOException e) {
    eventListener.callFailed(this, e);
    throw e;
  } finally {
    //请求完成之后,销毁此call,回收资源
    client.dispatcher().finished(this);
  }
}

Dispatcher的工作机制流程图

这里写图片描述
图片来源:https://blog.csdn.net/qq_16445551/article/details/78979306

Dispathcer对外的一些方法

cancelAll()

//结束掉所有的请求,包括同步、异步、等待队列中的请求
public synchronized void cancelAll() {
    for (AsyncCall call : readyAsyncCalls) {
      call.get().cancel();
    }

    for (AsyncCall call : runningAsyncCalls) {
      call.get().cancel();
    }

    for (RealCall call : runningSyncCalls) {
      call.cancel();
    }
  }

queuedCalls()

//返回当前的等待执行的请求
public synchronized List<Call> queuedCalls() {
   List<Call> result = new ArrayList<>();
   for (AsyncCall asyncCall : readyAsyncCalls) {
     result.add(asyncCall.get());
   }
   return Collections.unmodifiableList(result);
}

runningCalls()

//返回当前正在执行队列的中的请求
 public synchronized List<Call> runningCalls() {
   List<Call> result = new ArrayList<>();
   result.addAll(runningSyncCalls);
   for (AsyncCall asyncCall : runningAsyncCalls) {
     result.add(asyncCall.get());
   }
   return Collections.unmodifiableList(result);
 }

queuedCallsCount()

 //返回当前等待队列中请求的数量
 public synchronized int queuedCallsCount() {
    return readyAsyncCalls.size();
 }

runningCallsCount()

//返回执行队列中的请求数量,包括异步、同步
public synchronized int runningCallsCount() {
    return runningAsyncCalls.size() + runningSyncCalls.size();
}

猜你喜欢

转载自blog.csdn.net/qq_33768280/article/details/80754178