关于okhttp的线程管理思路

最近Android请求网络比较火的,官方都采用的http请求库就是okhttp了,此库做的优化比较好,效率比较高,我比较想了解其线程的管理,所以看了看源码:

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;
  }

khttp所使用的线程池,可以看出它是个没有上线的线程池,最大线程数可以是Integer.MAX_VALUE,那么它是怎么控制线程的数量的呢?

 private int maxRequests = 64;//最大的请求数量
  private int maxRequestsPerHost = 5;//同一主机的最大请求数量
  private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();//超过最大请求数量或者同一主机的最大请求数量时,请求放在此集合里

synchronized void enqueue(AsyncCall call) {
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      runningAsyncCalls.add(call);
      executorService().execute(call);
    } else {
      readyAsyncCalls.add(call);
    }
  }
runningAsyncCalls,这是一个集合,维护了所有的请求。runningCallsForHost,维护了所有的同一主机的请求。由上面的代码可以看出,当请求数量小于maxRequests时,并且同一主机的请求小于maxRequestsPerHost 时,线程池会开启线程执行请求的任务。当请求数量大于maxRequests时,或者同一主机的请求小于maxRequestsPerHost 时,请求会被添加到readyAsyncCalls 中,并不会执行。那么什么时候执行这些请求呢?

/** Used by {@code AsyncCall#run} to signal completion. */
  synchronized void finished(AsyncCall call) {
    if (!runningAsyncCalls.remove(call)) throw new AssertionError("AsyncCall wasn't running!");
    promoteCalls();
  }

可以看出,当线程里的任务执行完后,会执行此方法,此方法会执行promoteCalls();
private void promoteCalls() {
    if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
    if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.

    for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
      AsyncCall call = i.next();

      if (runningCallsForHost(call) < maxRequestsPerHost) {
        i.remove();
        runningAsyncCalls.add(call);
        executorService().execute(call);
      }

      if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
    }
  }

“`
可以看出,当一个线程的任务执行完了之后,会把此请求从runningAsyncCalls中移除,然后执行readyAsyncCalls中未执行的任务。

通过这样一个流程控制,可以把线程池的大小控制在64个线程以内,把同一主机的请求的线程控制在5个,这样当同一个项目中日志和业务请求一起并发时,不会影响app的使用,同时也可以控制子线程的数量,保证app的性能

总的来说,是通过自己维护三个集合来控制线程池的大小,优化性能的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值