OkHttp源码中Dispatcher和connectionPool线程池分析

在前面《OkHttp原理流程源码分析》中梳理分析了OkHttp中同步发起网络请求和异步发起网络请求,最终的请求分发是有Dispatcher分发器来完成的,Dispatcher分发器的实现中涉及到的线程池的应用代码,并未做分析,今天我们先看第一个线程池应用,Dispatcher中的线程池实现。

一、OkHttp中Dispatcher的线程池实现

异步网络请求最终会被Dispatcher统一管理调度,client.dispatcher().enqueue(new AsyncCall(responseCallback));,enquene()实现了入队列的逻辑。

public final class Dispatcher {
   
  synchronized void enqueue(AsyncCall call) {
   
    //正在运行请求中的call数<64&&同一主机地址运行请求中的call数<5
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
   
      //添加到运行中的管理队列中
      runningAsyncCalls.add(call);
      //直接调用executeService.execute方法,执行调用,后续就到拦截器流程了
      executorService().execute(call);
    } else {
   
      readyAsyncCalls.add(call);
    }
  }
}

这里我们主要分析一下这里的线程池,看一下executorService的实现,同样是在Dispatcher类的源码中:

public final class Dispatcher {
   
 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;
  }
}

上述代码中,通过new ThreadPoolExecutor创建,我们看一下这里使用的构造函数中的每个参数:

/**
 * 通过初始化参数和默认拒绝处理器创建一个线程池
 * @param corePoolSize 核心线程数,即使她们是idle状态,也会保留。除非通allCoreThreadTimeOut设置了,才可能销毁。

 * @param maximumPoolSize 在池子中允许的最大的线程数
 * @param keepAliveTime 当线程池中空闲线程数量超过corePoolSize时,多余的线程会在多长时间内
 * 被销毁
 * @param keepAliveTime的时间单位参数
 * @param workQueue 工作队列,在任务执行之前,持有任务集合。只有runable 任务通过excute方法被
 * 提交的才会被持有。
 * @param threadFactory 创建线程池的工厂
 * @throws IllegalArgumentException 非法参数异常         
 * @throws NullPointerException 空指针异常
 */
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory) {
   
    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
         threadFactory, defaultHandler);
}

在以上注释中,我们对创建线程池的构造方法,进行了参数解释。Dispatcher类中调用此构造函数传入的参数分别如下:

  • @param corePoolSize 核心线程数:0;
  • @param maximumPoolSize 在池子中允许的最大的线程数:Integer.MAX_VALUE
  • @param keepAliveTime 非核心线程存活时间:60 秒
  • @param keepAliveTime的时间单位参数 seconds
  • @param workQueue 工作队列:SynchronousQueue
  • @param threadFactory 创建线程池的工厂:Util.threadFactory工厂类

核心线程数为0,线程池中可以创建的线程数为整形的最大值。

工作队列为SynchronousQueue,这个队列的容量不是0就是1。

这样的线程池设计,是不是有问题呢?

理论上来讲,性能极好的情况下,这样的线程池,拥有最高的并发吞吐能力,为什么,你提交多少runable,线程池就立即执行,发现没有空闲的线程,就创建线程执行。

但实际上怎么可能有这么好的性能呢?当然OkHttp的设计者,也并没有不考虑这个问题,在为了让线程池本身具有很好的吞吐能力的同事,OkHttp对框架内部提交的任务,进行了自维护。也就是runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) ;使得最大并发线程就最多不超过64个。

其实这块的代码设计,是比较简单的。为什么要单独拿出来说呢,我觉得这种设计考虑挺好,既然是OkHttp框架自己处理任务的事情,就交给框架自己,另外框架内部还要处理同域名的域名请求的任务的提交,那就有框架自己同一来管理就好了。

这样的设计我觉得职责还是挺清晰的,线程池你就啥呀别管了,我给你你就执行就好了呗。

二、 OkHttp中ConnectionPool连接池的实现

《OkHttp原理流程源码分析》这篇文章中,关于ConnectionInterceptor,我们简单的分析了其主要流程如下:

/** 打开一个到目标服务器的连接以及执行下一个拦截器 */
public final class ConnectInterceptor implements Interceptor {
   
  public final OkHttpClient client;

  public ConnectInterceptor(OkHttpClient client) {
   
    this.client = client;
  }

  @Override public Response intercept(Chain chain) throws IOException {
   
    RealInterceptorChain realChain = (RealInterceptorChain) chain;
    Request request = realChain.request();
    StreamAllocation streamAllocation = realChain.streamAllocation();

    // We need the network to satisfy this request. Possibly for validating a conditional GET.
    boolean doExtensiveHealthChecks = !request.method().equals("GET");
    
    //关键代码
    HttpCodec httpCodec = streamAllocation.newStr
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hymKing

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值