深入OKHttp源码分析(二)----OkHttp任务调度核心类Dispatcher解析

OkHttp任务调度核心类Dispatcher解析

上一篇我们分析了okhttp的同步和异步请求的执行流程并进行了源码分析,深入OKHttp源码分析(一)----同步和异步请求流程和源码分析 那么今天我们来看看在整个执行流程中起到关键作用的Dispatcher调度类。首先我们来看看这个类中的几个全局变量

 /** Executes calls. Created lazily. */private @Nullable ExecutorService executorService;/** Ready async calls in the order they'll be run. */private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();/** Running asynchronous calls. Includes canceled calls that haven't finished yet. */private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();/** Running synchronous calls. Includes canceled calls that haven't finished yet. */private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
复制代码

我们先来看下面三个变量 readyAsyncCalls:等待执行的异步任务队列,用来存放异步任务,如果线程池中的任务数量已经超过或已经达到指定的最大的任务数,那么久将异步任务放入这个队列中。 runningAsyncCalls:正在执行的异步任务队列,如果线程池中的任务数量小于指定的最大任务数,就将异步任务添加到这个队列中, runningSyncCalls:正在执行的同步任务队列

接着回来我们看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;}
复制代码

我们可以看到,果然是new出来一个线程池并复制给了executorService,我们来看下线程池的构造函数中的参数,来一一分析下: 第一个参数0,指的是这个线程池中的核心线程数量,如果线程池中没有任务的话,那么非核心线程在经过一段时间的等待后就会关闭,以节省资源。 第二个参数Integer.MAX_VALUE,这个参数指的是这个线程池中的最大线程数,设置成了integer的最大值,我们知道,这个值是非常大的,如果真的创建了这么多的线程,那么我们的手机不会挂掉吗???其实不会的,因为okhttp在其他地方已经进行了判断,如果线程池中的线程数量达到了指定的数值,就不会将任务添加到线程池中,也就不会新建线程了。具体是在哪里判断的,我们稍后介绍。 第三个参数60和第四个参数TimeUnit.SECONDS,这个指的就是空闲线程的存活时间,第三个参数指定数值,第四个参数指定单位。 第五个参数new SynchronousQueue():其实就是线程池中的线程的管理队列 第六个参数Util.threadFactory("OkHttp Dispatcher", false):这个是线程的创建工厂,线程的创建就是通过第六个参数进行的,有兴趣的朋友可点进去继续看下,我们就不贴出来啦。

我们再来看下上一篇遇到过的一个方法

synchronized void enqueue(AsyncCall call) {if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {runningAsyncCalls.add(call);executorService().execute(call);} else {readyAsyncCalls.add(call);}}
复制代码

我们看下if语句的条件中的两个变量maxRequests,maxRequestsPerHost,我们看下定义,

  private int maxRequests = 64;private int maxRequestsPerHost = 5;
复制代码

这两个值是什么意思呢,其实,maxRequests就是线程池中的最大任务数,当线程池中的任务数量达到这个值之后,就不再往线程池中继续添加任务,所以,即使在创建线程池的时候指定了线程池的最大任务数是integer的最大值,也是不可能达到的,这就是原因。maxRequestsPerHost是每个主机的最大请求数,当线程池中的任务对同一个主机的请求达到这个数值之后,就不能继续往线程池中添加对这个主机的请求任务,不知道这样说大家能不能理解???? 我们回过头来看下这条语句runningCallsForHost(call),点进去看下这个方法的实现

 private int runningCallsForHost(AsyncCall call) {int result = 0;for (AsyncCall c : runningAsyncCalls) {if (c.get().forWebSocket) continue;if (c.host().equals(call.host())) result++;}return result;}
复制代码

我们可以看到,里面是对线程池中正在执行的任务进行遍历操作,当要添加的任务的请求的主机和正在进行的任务的主机一致,result就加1,最后得到对这个主机的请求数量,然后在前面的if语句中进行判断是否小于指定的值,如果小于,就将异步任务添加到正在执行的异步任务队列中,并添加到线程池中,否则就添加到等待的异步任务队列中。

我们再来看一个前面分析过的方法,finished方法,这个方法在哪里会被调用呢?如果你不清楚,请看前面一篇文章的分析,我们看下这个方法的实现

 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!");if (promoteCalls) promoteCalls();runningCallsCount = runningCallsCount();idleCallback = this.idleCallback;}if (runningCallsCount == 0 && idleCallback != null) {idleCallback.run();}}
复制代码

在加锁的代码块中,首先将这个异步请求的任务从执行的队列中移除,然后我们看下这句

if (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.}}
复制代码

首先判断当前正在运行的队列中的任务数量是否达到了指定的数值,如果等于或大于指定数值,就返回,接着判断等待队列是否为空,如果为空,说明没有要添加的任务,也返回即可。 下面对等待的任务队列进行遍历,首先取出一个异步任务,判断该任务请求的主机地址在正在执行的队列中的数量是否达到了指定的最大任务数,如果没有达到,就从等待队列中移除,并添加到正在运行的队列中,并加入线程池中执行。 最后判断正在运行的任务队列中的任务数量是否达到了指定的最大任务数,如果大于最大任务数,就跳出for循环,否则,就继续从等待队列中取出任务进行操作。 这个方法分析完了,我们回到finished方法中,继续往下看

runningCallsCount = runningCallsCount();
复制代码

上一篇我们介绍过,这个语句只是重新计算了正在执行的任务数量,包括同步和异步任务。 finished方法最后部分是判断运行任务数量是否为0,如果没有了运行任务,就执行回收线程进行资源回收操作。 到此为止呢,我们就将okhttp的任务调度核心类Dispatcher的主要代码又分析了一遍,相信大家能对这个类有了较为深刻的认识了,这个类的主要功能就是对同步和异步任务进行调度处理,相当于任务的指挥者,大概就像是十字路口的交警同志吧,让你等你就等,让你走你就得走,可能比喻不是非常恰当,只要大家都明白即可,下一篇我们就对okhttp的拦截器进行介绍和分析。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/283603.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C# 二十年语法变迁之 C# 10参考

C# 二十年语法变迁之 C# 10参考https://benbowen.blog/post/two_decades_of_csharp_vi/自从 2000 年引入 C# 以来&#xff0c;该语言的规模已经大大增加&#xff0c;我不确定任何人是否有可能随时对每个语言特性都有深入的了解。因此&#xff0c;我想写一系列快速参考文章&…

IT圈中的Bug的类型与历史

美国计算机科学家、图灵奖获得者詹姆斯尼古拉格雷(Jim Gray)&#xff0c;在他的著名的论文“Why do computers stop and what can be done about it?”中首次提出了程序bug的类型&#xff0c;比如玻尔bug(Bohrbug)、 海森堡bug(Heisenbugs)等用著名科学家名称命名的bug。后来又…

Windows Nano Server安装配置详解03:远程管理Nano Server

远程管理Nano Server主要是通过使用远程powershell的方式。首先&#xff0c;我们把Nano Server的登录凭据保存到$cred变量之中&#xff0c;如图。其次&#xff0c;把远程Nano Server服务器添加到远程管理机本地的trustedHosts中&#xff0c;否则会报下面的错误&#xff0c;如图…

你和阿里资深架构师之间,差的不仅仅是年龄(进阶必看)

导读&#xff1a;阅读本文需要有足够的时间&#xff0c;笔者会由浅到深带你一步一步了解一个资深架构师所要掌握的各类知识点&#xff0c;你也可以按照文章中所列的知识体系对比自身&#xff0c;对自己进行查漏补缺&#xff0c;觉得本文对你有帮助的话&#xff0c;可以点赞关注…

[luoguP2601] [ZJOI2009]对称的正方形(二维Hash + 二分 || Manacher)

传送门 很蒙蔽&#xff0c;不知道怎么搞。 网上看题解有说可以哈希二分搞&#xff0c;也有的人说用Manacher搞&#xff0c;Manacher是什么鬼&#xff1f;以后再学。 对于这个题&#xff0c;可以从矩阵4个角hash一遍&#xff0c;然后枚举矩阵中的点&#xff0c;再二分半径。 但是…

Semaphore详解

Semaphore基本使用场景 Semaphore的基本使用场景是限制一定数量的线程能够去执行. 举个简单的例子: 一个单向隧道能同时容纳10个小汽车或5个卡车通过(1个卡车等效与2个小汽车), 而隧道入口记录着当前已经在隧道内的汽车等效比重. 比如1个小汽车和1个卡车, 则隧道入口显示3. 若…

PerfView专题 (第六篇):如何洞察 C# 中 GC 的变化

一&#xff1a;背景 在洞察 GC 方面&#xff0c;我觉得市面上没有任何一款工具可以和 PerfView 相提并论&#xff0c;这也是为什么我会在 WinDbg 之外还要学习这么一款工具的原因&#xff0c;这篇我们先简单聊聊 PerfView 到底能洞察 GC 什么东西&#xff1f;二&#xff1a;洞察…

Linux_日志管理介绍(一)

一、介绍1、CentOS 6.x中日志服务已经由rsyslogd取代了原先的syslogd服务&#xff0c;但是rsyslogd是和syslogd服务相兼容的2、除了系统默认的日志之外&#xff0c;采用RPM方式安装的系统服务也会默认把日志记录在/var/log/目录中&#xff08;源码包安装的服务日志是在源码包指…

如何将exe文件添加到开机启动

1、先创建exe文件的快捷方式 2、打开windows的startup启动目录&#xff08;针对win10以上&#xff09; windows有两个以上startup目录&#xff0c;一个是针对所有用户有效的&#xff0c;另外是每个用户下边有一个&#xff1a; 针对当前用户 &#xff1a; C:\Users\{当前用户}\A…

mysql重连,连接丢失:The last packet successfully received from the server--转载

1.1 错误信息&#xff1a; Caused by: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: The last packet successfully received from the server was 20,820,001 milliseconds ago. The last packet sent successfully to the server was 20,820,002 milliseconds…

.NET MAUI 跨平台应用程序 (Windows App 和 Android )示例

也就前周&#xff0c;.Net MAUI正式版出来了 &#xff0c;一个支持跨平台的UI框架,Linux支持情况官网也没说&#xff0c;按理来说应该也是支持的&#xff0c;刚好&#xff0c;我最近也在研究GUI的基本原理&#xff0c;微软出品还是值得深入研究一下的&#xff0c;就先来个样例&…

OpenStack 计算节点删除

前提 计算节点中一个僵尸计算节点存在&#xff0c;而里面的CPU数目在总物理CPU中&#xff0c;导致认为当前能创建实例。而实际没有这么多资源。其中node-11为僵尸节点。 原因 删除计算节点不能直接格式化该服务器&#xff0c;否则在控制节点的数据库上会存在该计算节点的数据。…

PHP 7.2 新功能介绍

PHP 7.2 已經在 2017 年 11 月 30 日 正式發布 。這次發布包含新特性、功能&#xff0c;及優化&#xff0c;以讓我們寫出更好的代碼。在這篇文章裡&#xff0c;我將會介紹一些 PHP 7.2 最有趣的語言特性。 你可以在 Requests For Comments 頁面查看完整的更動清單。 核心改进 参…

C盘空间不够 mklink解决VScode扩展迁移到其他盘

第一步 将C盘C:\Users\JackieZheng\.vscode文件夹剪切到D:\vscode中去 第二步 以管理员身份运行cmd&#xff0c;执行如下命令&#xff0c;建立符号链接在管理员身份下的cmd中输入如下命令 mklink /D "C:\Users\JackieZheng\.vscode" "D:\vscode\.vscode" 两…

如何打造单文件 Blazor Server 应用

前言上次&#xff0c;我们介绍了《如何打造单文件前后端集成 ASP.NET Core 应用》。但是&#xff0c;网友说&#xff0c;对于 Blazor Server 项目此方法无效。于是&#xff0c;我们测试了一下&#xff1a;BlazorApp1.csproj<Project Sdk"Microsoft.NET.Sdk.Web"&g…

正则化笔记

吉谱斯现象Gibbs&#xff08;又叫吉谱斯效应&#xff09;&#xff1a; 用有限项傅里叶级数表示有间断点的信号时&#xff0c;在间断点附近不可避免的会出现振荡和超量。超量的幅度不会随所取项数的增加而减小。只是随着项数的增多&#xff0c;振荡频率变高&#xff0c;并向间断…

Android线程池详解

引入线程池的好处 1&#xff09;提升性能。创建和消耗对象费时费CPU资源 2&#xff09;防止内存过度消耗。控制活动线程的数量&#xff0c;防止并发线程过多。 我们来看一下线程池的简单的构造 [html] view plaincopy print?public ThreadPoolExecutor(int corePoolSize, …

win11下vscode 自动升级失败 There was an error while marking a file for deletion

当升级vscode时出现下方报错&#xff1a; There was an error while marking a file for deletion:Failed to mark file for deletion:拒绝访问.Please verify there are no Visual Studio Code processes still executing既然是“拒绝访问”应该是权限问题&#xff0c;关闭vsc…

MySQL添加新用户、为用户创建数据库、为新用户分配权限

https://blog.csdn.net/u013216667/article/details/70158452 登录MySQL mysql -u root -p 添加新用户 允许本地 IP 访问 localhost, 127.0.0.1 create user testlocalhost identified by 123456;允许外网 IP 访问 create user test% identified by 123456; 刷新授权 flush p…

【mysql必知必会】第十二章 汇总数据

1、聚集函数&#xff08;aggregate function&#xff09;&#xff1a;运行在行组上&#xff0c;计算和返回单个值得函数。 AVG&#xff08;&#xff09;  返回某列的平均值 COUNT&#xff08;&#xff09;  返回某列的行数 MAX&#xff08;&#xff09;  返回某列的最大值…