记低版本okhttp超时会导致死锁
一、问题起源
在处理一次生产环境cpu拉满问题时,把日志拉下来看发现很多http请求调用出错,项目使用的是okhttp 3.8.1版本。
二、问题描述
问题出在okhttp3.Dispatcher.finished(Dispatcher.java:201)代码如下:
void finished(AsyncCall call) {finished(runningAsyncCalls, call, true);
}
void finished(RealCall call) {finished(runningSyncCalls, call, false);
}
private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {int runningCallsCount;Runnable idleCallback;synchronized (this) { //201行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();}
}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.}
}
三、分析代码
在OkHttpClient中final Dispatcher dispatcher; 作为成员对象,而我们代码中OkHttpClient作为连接池是单例的,这里是对dispatcher做synchronized。
追踪代码发现,在finished的调用方法中,我们方法中使用的是异步AsyncCall,而这里synchronized方法中的promoteCalls被置为true。所以会调用promoteCalls()方法, 而promoteCalls()方法中会继续调用executorService().execute(call);,就是这里,问题大了,synchronized中执行http请求,那上面代码中的超时不就长时间占用锁了?怪不得进程blocked了。
关于线程的BLOCKED,需要知道:
- java.lang.Thread.State: BLOCKED:等待监视器锁而被阻塞的线程的线程状态,当进入 synchronized 块/方法或者在调用 wait()被唤醒/超时之后重新进入 synchronized 块/方法, 但是锁被其它线程占有,这个时候被操作系统挂起,状态为阻塞状态。若是有线程长时间处于 BLOCKED 状态,要考虑是否发生了死锁(deadlock)的情况。
- blocked的线程不会消耗cpu,但频繁的频繁切换线程上下文会导致cpu过高。线程被频繁唤醒,而又由于抢占锁失败频繁地被挂起. 因此也会带来大量的上下文切换, 消耗系统的cpu资源。
四、解决方案
okttp关于这个问题已经有过解答:
Dispatcher no longer has quadratic behaviour by iamdanfox · Pull Request #4581 · square/okhttp · GitHub
[improvement] okhttp 3.12.0 -> 3.13.1, to pick up perf improvements to okhttp3.Dispatcher by iamdanfox · Pull Request #940 · palantir/conjure-java-runtime · GitHub
解决方案就简单多了:升级okhttp到3.14.9,虽然目前最新稳定版本为4.9.3,但是OkHttp 4发布,从Java切换到Kotlin。谨慎一点,还是小版本升级吧。
在3.14.9中,这部分代码被优化为:
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 (asyncCall.callsPerHost().get() >= maxRequestsPerHost) continue; // Host max capacity.i.remove();asyncCall.callsPerHost().incrementAndGet();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;
}
执行HTTP请求被移出了synchronized方法了。
相关文章:
记低版本okhttp超时会导致死锁
一、问题起源 在处理一次生产环境cpu拉满问题时,把日志拉下来看发现很多http请求调用出错,项目使用的是okhttp 3.8.1版本。 二、问题描述 问题出在okhttp3.Dispatcher.finished(Dispatcher.java:201)代码如下: void finished(AsyncCall c…...
idea必装的插件 Spring Boot Helper 插件(创建 Spring Boot 项目)
Spring Spring让Java程序更加快速,简单和安全.Spring对于速度、简单性和⽣产⼒的关注使其成为 世界上最流⾏的Java框架。Spring官⽅提供了很多开源的项⽬,覆盖范围从Web开发到⼤数据,Spring发展到了今天,已经形成了⾃ ⼰的⽣态圈.我们在开发时,也倾向于使⽤Spring官⽅提供的技术…...
Scrum(敏捷开发)的前端定位
1. Scrum(敏捷开发)的开发流程 Scrum将整个开发过程分为多次迭代(称为Sprint,冲刺),一般为期2~4周,最常见的为2周。Scrum并非以一段时间集中完成一个过程,而是将所有过程中必须的每一部分集中在这段时间内完成。需求、设计、编码、测试、上线都必须在一个迭代中完成,每…...
uniapp缓存对象数组
需求:使用uniapp,模拟key(表名)增删改查对象数组,每个key可以单独操作,并模拟面对对象对应表,每个key对应的baseInstance 类似一个操作类,当然如果你场景比较简单,可以改…...
腾讯云优惠券免费领取入口整理分享
腾讯云作为国内领先的云服务提供商,为了回馈用户的支持和信任,经常推出各种优惠活动,并提供优惠券供用户使用。本文将整理和分享腾讯云优惠券的免费领取入口,帮助用户在购买腾讯云产品时享受更多的优惠和福利。 一、腾讯云优惠券介…...
功率放大器在PZT陶瓷薄膜压电传感器研究中的应用
随着科技的进步和工业发展的需求,对于压力测量和控制的需求日益增加。压力传感器作为一种关键的传感器器件,在机械、自动化、医疗、航空等多个领域都有广泛应用。PZT陶瓷薄膜压电传感器由于其响应速度快、精度高、稳定性好等优点,成为了许多应…...
Anaconda创建新的虚拟环境及Jupyter Notebok中、PyCharm中环境的使用
Anaconda创建新的虚拟环境 在windows开始菜单中【徽标键】,查找Anaconda文件夹并打开【Anaconda Prompt】 查看已有虚拟环境 conda env list1.创建 conda create --name mytest python3.7 # 创建一个名称为mytest,python版本为3.7的虚拟环境输入【…...
[QT] 如果你怎么试HTTP下载文件得到的QNetworkReply的readAll()都是空数据(长度为0),请看这里
1,首先你对比看看QT官方给出的例子 Download Data from URL - Qt Wiki 2,再看看是不是要设置重定向,如果要,要设置一下 QNetworkRequest request(imageUrl); request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, …...
使用docker部署flask接口服务 一
文章目录 一:说明二:dockerfile 参数说明1. 一般常用的 参数,以及它的含义2. 我自己的 dockerfile 三:示例操作1. Gunicorn Gevent启动服务的好处2. 用Gunicorn Gevent的好处:3. Gunicorn Gevent的 使用示例4. 创建…...
超实用的跟圈和一键转发好友朋友圈功能
一键转发朋友圈/跟圈 想转发别人的朋友圈内容,通常需要手动复制粘贴,一个个复制保存实在是太麻烦耗费时间。 有时候咱也不可能随时都看朋友圈嘛,那又想及时转发朋友的圈的,有什么办法可以轻松实现呢? 操作步骤 单击…...
口袋参谋:如何一键获取竞品数据?这招实用!
在淘宝天猫上开店,市场竞争日益激烈,想要做好店铺,我们就不得不去分析竞品的数据了。 很多卖家开店后,一上来就直接卡在类目前10,折腾了一两个月才发现自己对标错了对象,最终竹篮打水一场空。 所以&…...
python 生成html文件并端口展示
1.生成相关的html文件 import json import os import calc import requests import numpy as npwith open(picture, r,encodingutf-8) as f:lines f.readlines() html <html>\n<html lang"zh">\n<head>\n<meta charset"UTF-8">…...
二进制部署 Kubernetes(master和node)
二进制搭建 Kubernetes v1.20 k8s集群master01:20.0.0.101 kube-apiserver kube-controller-manager kube-scheduler etcd k8s集群master02:20.0.0.106 k8s集群node01:20.0.0.102 kubelet kube-proxy docker k8s集群node02:20.0…...
【计算机网络】IP协议的相关特性
IP协议:互联网的核心组件 在当今高度数字化的世界中,互联网已成为人们生活、工作不可或缺的一部分。而在这个庞大的网络中,IP协议(Internet Protocol)作为核心的通信协议,发挥着至关重要的作用。本文将详细…...
如何在Potplayer中使用公网访问群晖WebDav?
文章目录 1 使用环境要求:2 配置webdav3 测试局域网使用potplayer访问webdav4 内网穿透,映射至公网5 使用固定地址在potplayer访问webdav 国内流媒体平台的内容让人一言难尽,就算是购买了国外的优秀作品,也总是在关键剧情上删删…...
如果你有一台服务器,你最想做那些事?
如果有一台服务器,可以做很多有趣的事情。本文将介绍服务器的基本知识,假设你拥有一台服务器后该如何使用它,以及管理服务器的最佳实践。 首先,让我们了解一下什么是服务器。服务器是指在网络上提供各种服务的计算机,如…...
Unity中Shader的Fallback
文章目录 前言一、解决 Pass 复用的方案方案一:使用之前的UsePass方案,把ShadowCaster的Pass提出来到一个单独的Shader中,在使用的时候直接使用 UsePass方案二:使用Fallback功能 前言 Unity中Shader的Fallback,我们在…...
“菜鸟”程序员逆袭:独立开发iOS音乐应用,年底参加Amazon DeepRacer 全球锦标赛
“致一年前的小木土:任务完成。” 6月30日,在获得2023 Amazon DeepRacer自动驾驶赛车企业总决赛中国区冠军三天后的深夜,杜键文发了这条朋友圈,并配上比赛现场的9张图。 “小木土”是杜键文的网名,取其姓氏ÿ…...
nginx测试rewrite
nginx测试rewrite last :相当于 Apache 里的(L)标记,表示完成rewrite 匹配; break: 本条规则匹配完成后,终止匹配,不再匹配后面的规则。 # 其中last 和 break 用来实现 URL 重写时,浏览器地址栏URL 地址不变 redirect: 返回 302 …...
qt 多语言版本 QLinguist使用方法
在使用qt开发一款软件时,可能需要考虑显示文本中英文等多语言版本。可以使用qt语言家的方式实现。 步骤: 1、代码中给控件设置文本时,记得带上QObject::tr() 2、工程pro文件中加入 TRANSLATIONS demo2_en.ts 3、Qt creator点击“工具”—“外…...
测试微信模版消息推送
进入“开发接口管理”--“公众平台测试账号”,无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。 获取access_token: 自定义模版消息: 关注测试号:扫二维码关注测试号。 发送模版消息: import requests da…...
深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录
ASP.NET Core 是一个跨平台的开源框架,用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录,以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...
深入剖析AI大模型:大模型时代的 Prompt 工程全解析
今天聊的内容,我认为是AI开发里面非常重要的内容。它在AI开发里无处不在,当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗",或者让翻译模型 "将这段合同翻译成商务日语" 时,输入的这句话就是 Prompt。…...
23-Oracle 23 ai 区块链表(Blockchain Table)
小伙伴有没有在金融强合规的领域中遇见,必须要保持数据不可变,管理员都无法修改和留痕的要求。比如医疗的电子病历中,影像检查检验结果不可篡改行的,药品追溯过程中数据只可插入无法删除的特性需求;登录日志、修改日志…...
深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法
深入浅出:JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中,随机数的生成看似简单,却隐藏着许多玄机。无论是生成密码、加密密钥,还是创建安全令牌,随机数的质量直接关系到系统的安全性。Jav…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...
vue3 字体颜色设置的多种方式
在Vue 3中设置字体颜色可以通过多种方式实现,这取决于你是想在组件内部直接设置,还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法: 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...
工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配
AI3D视觉的工业赋能者 迁移科技成立于2017年,作为行业领先的3D工业相机及视觉系统供应商,累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成,通过稳定、易用、高回报的AI3D视觉系统,为汽车、新能源、金属制造等行…...
企业如何增强终端安全?
在数字化转型加速的今天,企业的业务运行越来越依赖于终端设备。从员工的笔记本电脑、智能手机,到工厂里的物联网设备、智能传感器,这些终端构成了企业与外部世界连接的 “神经末梢”。然而,随着远程办公的常态化和设备接入的爆炸式…...
Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战
说明:这是一个机器学习实战项目(附带数据代码文档),如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下,风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...
