OkHttp的分发器线程池

2020-04-06  本文已影响0人  Mr_Hongdou
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;
  }

OkHttp 的分发器中的线程池定义如上,其实就和 Executors.newCachedThreadPool() 创建的线程一样,分析一下参数:

当需要线程池执行任务时,有如下几种情况:

a. 当前线程数量小于核心线程数,将新建(核心)线程来处理被添加的任务;

b. 当前线程数量大于等于核心线程数,存在空闲线程,将使用空闲线程来执行新任务;

c. 当前线程数量大于等于核心线程数,不存在空闲线程,新任务将被添加到等待队列,

​ 添加成功则等待空闲线程;

​ 添加失败: (1). 线程数小于 maximumPoolSize,新建线程执行任务;

​ (2). 线程数大于等于 maximunPoolSize,拒绝此任务。

可以指定不同的等待队列,这样会有不同的线程池排队机制。一般来说,等待队列 BlockingQueue 有:ArrayBlockingQueueLinkedBlockingQueueSynchronousQueue

  1. ArrayBlockingQueue: 基于数组的阻塞队列,初始化需要指定固定大小。

当使用此队列时,向线程池提交任务,会首先加入到等待队列中,当等待队列满了之后,再次提交任务,尝试加入队列就会失败,这时就会检查如果当前线程池中的线程数未达到最大线程,则会新建线程执行新提交的任务。所以最终可能出现后提交的任务先执行,而先提交的任务一直在等待。

  1. LinkedBlockingQueue:基于链表实现的阻塞队列,初始化可以指定大小,也可以不指定。

当指定大小后,行为就与 ArrayBlockingQueue 一致。而如果未指定大小,则会使用默认的Integer.MAX_VALUE 作为队列的大小。这时候就会出现线程池的最大线程数参数无用,因为无论如何,向线程池提交任务加入等待队列都会成功。最终意味着所有任务都是在核心线程执行。如果核心线程一直被占用,那就一直等待。

  1. SynchronousQueue:无容量的队列。

    使用此队列意味着希望获得最大并发量。因为无论如何,向线程池提交任务,往队列提交任务都会失败。而失败后如果没有空闲的非核心线程,就会检查如果当前的线程池中的线程数未达到最大线程,则会新建线程执行新提交的任务。完全没有任何等待,唯一制约它的就是最大的线程数量。因此一般配合Integer.MAX_VALUE实现真正的无等待。

但需要注意的是进程的内存是存在限制的,而每一个线程都需要分配一定的内存。所以线程并不是无限个数。那么当设置最大线程数为Integer.MAX_VALUE时,OkHttp同时还有最大请求任务个数(默认64)和每个域名最大请求数(默认5)的限制。

上一篇下一篇

猜你喜欢

热点阅读