okhttp源码学习二

一、Dispatcher类详解
1.线程池ExecutorService

private @Nullable ExecutorService 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;
}

由上面代码可以得出Dispatcher内部实现了懒加载的无边界线程池

  • SynchronousQueue的每个插入操作必须是等待另外一个线程的移除操作,同样任何一个移除操作都等待另外一个线程的插入操作。因此队列内部其实没有任何一个元素,或者说容量为0,只有移除元素才有元素,显然这是一个快速传递元素的方式,也就是说在这种情况下元素总是以最快的方式从插入者(生产者)传递给移除者(消费者),这在多任务队列中最快的处理任务方式。对于高频请求场景,无疑是最合适的。
  • 该线程池不保留任何最小线程,随时创建更多的线程,如果线程空闲后,只能存活60秒。所以也就是说如果收到10个请求,线程池会创建10个线程,当完成后60秒会关闭所有10个线程。这样设成不设上限的线程,让I/O任务不会长时间卡在阻塞上。

2.发起请求
整个框架主要通过Call来封装每一次请求。同时Call持有OkHttpClient的Request,每次同步、异步请求都通过Dispatcher来调度

  • 同步:Dispatcher在执行同步Call时,并没有做什么处理,只把Call添加到同步请求队列中,具体的操作还是在RealCall中完成的
synchronized void executed(RealCall call) {
    runningSyncCalls.add(call);
  }
  • 异步:首先会把AsyncCall(其实是Runnable)加到等待执行队列中。接着走到promoteAndExecute()方法中,该方法会先遍历等待队列,如果请求数没超过64,并且同一主机请求数不超过5,就会把当前遍历到的AsyncCall从等待队列中移除,再把它加到异步请求队列中。
void enqueue(AsyncCall call) {
    synchronized (this) {
      readyAsyncCalls.add(call);
    }
    promoteAndExecute();
}
private boolean promoteAndExecute() {
    assert (!Thread.holdsLock(this));

    List<AsyncCall> executableCalls = new ArrayList<>();
    boolean isRunning;
    synchronized (this) {
      for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
        AsyncCall asyncCall = i.next();

        if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
        if (runningCallsForHost(asyncCall) >= maxRequestsPerHost) continue; // Host max capacity.

        i.remove();
        executableCalls.add(asyncCall);
        runningAsyncCalls.add(asyncCall);
      }
      isRunning = runningCallsCount() > 0;
    }

    for (int i = 0, size = executableCalls.size(); i < size; i++) {
      AsyncCall asyncCall = executableCalls.get(i);
      asyncCall.executeOn(executorService());
    }

    return isRunning;
  }

3.结束请求
从准备到运行结束,每个Call都会走到finished方法

private <T> void finished(Deque<T> calls, T call) {
    Runnable idleCallback;
    synchronized (this) {
      // 请求结束,从队列中移除
      if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
      idleCallback = this.idleCallback;
    }
	// 从等待请求队列中拿AsyncCall,放到请求队列中,从线程池中取线程执行该请求
    boolean isRunning = promoteAndExecute();

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

promoteAndExecute方法负责ready的Call到running的Call的转化,具体的执行都是在RealCall中,同步是RealCall的execute方法,异步是AsyncCall的execute方法。里面都是调用RealCall的getResponseWithInterceptorChain方法来实现责任链的调用。

二、OkHttp任务调度
1.同步

  • 调用RealCall的execute方法里的execute(this)
@Override public Response execute() throws IOException {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    timeout.enter();
    eventListener.callStart(this);
    try {
      client.dispatcher().executed(this);
      Response result = getResponseWithInterceptorChain();
      if (result == null) throw new IOException("Canceled");
      return result;
    } catch (IOException e) {
      e = timeoutExit(e);
      eventListener.callFailed(this, e);
      throw e;
    } finally {
      client.dispatcher().finished(this);
    }
  }
  • 在Dispatcher的execute方法进行入队操作
synchronized void executed(RealCall call) {
    runningSyncCalls.add(call);
}
  • 执行getResponseWithInterceptorChain方法,进入拦截器链,然后进行请求,拿到Response并返回
  • 任务执行完毕,调用Dispatcher的finished方法,将任务移出队列
/** Used by {@code Call#execute} to signal completion. */
void finished(RealCall call) {
    finished(runningSyncCalls, call);
}

2.异步

  • 调用RealCall的enqueue方法里的enqueue(new AsyncCall(responseCallback))
@Override public void enqueue(Callback responseCallback) {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    eventListener.callStart(this);
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }
  • 在Dispatcher的enqueue方法进行入队操作,把Call加到等待请求的队列中
void enqueue(AsyncCall call) {
    synchronized (this) {
      readyAsyncCalls.add(call);
    }
    promoteAndExecute();
}
  • promoteAndExecute方法将等待队列中的任务取出来,放到请求队列。前提是要满足条件,请求数不超过64,同一请求的数量不超过5
private boolean promoteAndExecute() {
    assert (!Thread.holdsLock(this));

    List<AsyncCall> executableCalls = new ArrayList<>();
    boolean isRunning;
    synchronized (this) {
      for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
        AsyncCall asyncCall = i.next();

        if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
        if (runningCallsForHost(asyncCall) >= maxRequestsPerHost) continue; // Host max capacity.

        i.remove();
        executableCalls.add(asyncCall);
        runningAsyncCalls.add(asyncCall);
      }
      isRunning = runningCallsCount() > 0;
    }

    for (int i = 0, size = executableCalls.size(); i < size; i++) {
      AsyncCall asyncCall = executableCalls.get(i);
      asyncCall.executeOn(executorService());
    }

    return isRunning;
  }
  • 线程池执行execute方法
executorService.execute(this);
  • 执行AsyncCall的execute方法
@Override protected void execute() {
      boolean signalledCallback = false;
      timeout.enter();
      try {
        Response response = getResponseWithInterceptorChain();
        if (retryAndFollowUpInterceptor.isCanceled()) {
          signalledCallback = true;
          responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
        } else {
          signalledCallback = true;
          responseCallback.onResponse(RealCall.this, response);
        }
      } catch (IOException e) {
        e = timeoutExit(e);
        if (signalledCallback) {
          // Do not signal the callback twice!
          Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
        } else {
          eventListener.callFailed(RealCall.this, e);
          responseCallback.onFailure(RealCall.this, e);
        }
      } finally {
        client.dispatcher().finished(this);
      }
    }
  • 执行getResponseWithInterceptorChain方法,进入拦截器链,然后进行请求,拿到Response
  • 如果是正常拿到的response,则调用responseCallback.onResponse方法将响应返回
  • 请求执行完毕,调用Dispatcher的finished方法,将请求进行出队处理,再去判断等待队列是否有请求,满足条件就加入请求队列(是一个继续入队的操作)
void finished(AsyncCall call) {
    finished(runningAsyncCalls, call);
}

三、OkHttp任务调度优点

  • 使用Dispatcher进行任务调度,实现很好的解耦,与线程池配合实现了高并发,低阻塞,提高请求效率
  • 请求Call通过Deque作为存储集合,很好地控制先进先出,保证请求顺序
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值