记低版本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方法了。

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

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

相关文章

PHP 危险函数2-代码执行语句

代码执行语句 eval() 不是函数&#xff0c;不能被动态调用&#xff0c;并且需要以 ;结束 直接输出&#xff0c;不执行 <?php$code"phpinfo();";echo $code;?>eval() 语句执行 <?php$code"phpinfo();";eval($code); // eval 不是函数&am…

vue3中常见的组合式API

一、toRef 和 toRefs 应用&#xff1a;要将响应式对象中的某个属性单独提供给外部使用时。 语法&#xff1a; toRef语法&#xff1a;const name toRef(person, name) toRefs语法&#xff1a;toRefs(person)&#xff0c;如果在return中直接写&#xff0c;需要用...(展开运算符…

【TGRS 2023】RingMo: A Remote Sensing Foundation ModelWith Masked Image Modeling

RingMo: A Remote Sensing Foundation Model With Masked Image Modeling, TGRS 2023 论文&#xff1a;https://ieeexplore.ieee.org/stamp/stamp.jsp?tp&arnumber9844015 代码&#xff1a;https://github.com/comeony/RingMo MindSpore/RingMo-Framework (gitee.com) …

软件测试之【单元测试、系统测试、集成测试】

一、单元测试的概念 单元测试&#xff08;Unit Testing&#xff09;是对软件基本组成单元进行的测试&#xff0c;如函数&#xff08;function或procedure&#xff09;或一个类的方法&#xff08;method&#xff09;。当然这里的基本单元不仅仅指的是一个函数或者方法&#xff…

Python:实现日历功能

背景 日常生活中&#xff0c;每天都要用到日历&#xff0c;日历成为我们生活中的必需品&#xff0c;那么如何制作日历呢&#xff0c;其实方法有很多&#xff0c;可以直接在excel中制作&#xff0c;也可以手画等等。 学习过编程的朋友&#xff0c;能否想到用Python编写一…

【Pytorch】Pytorch学习笔记02 - 单变量时间序列 LSTM

目录 说明简单神经网络LSTM原理Pytorch LSTM生成数据初始化前向传播方法训练模型自动化模型构建 总结参考文献 说明 这篇文章主要介绍如何使用PyTorch的API构建一个单变量时间序列 LSTM。文章首先介绍了LSTM&#xff0c;解释了它们在时间序列数据中的简单性和有效性。然后&…

Elasticsearch常见错误

一 read_only_allow_delete" : "true" 当我们在向某个索引添加一条数据的时候,可能(极少情况)会碰到下面的报错: {"error": { "root_cause": [ { "type": "cluster_block_exception", "r…

智慧垃圾站:AI视频智能识别技术助力智慧环保项目,以“智”替人强监管

一、背景分析 建设“技术先进、架构合理、开放智能、安全可靠”的智慧环保平台&#xff0c;整合环境相关的数据&#xff0c;对接已建业务系统&#xff0c;将环境相关数据进行统一管理&#xff0c;结合GIS技术进行监测、监控信息的展现和挖掘分析&#xff0c;实现业务数据的快速…

每日一练——快速合并2个有序数组

每日一练来喽~~~ 今天up主为大家分享一个&#xff0c;快速合并2个有序数组的法子&#xff0c;注意听哟&#xff01; 题目&#xff1a; 给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2&#xff0c;另有两个整数 m 和 n &#xff0c;分别表示 nums1 和 nums2 中的元素数…

[Docker]二.Docker 镜像,仓库,容器介绍以及详解

一.Docker 镜像,容器,仓库的简单介绍 通俗来讲:镜像相当于VM虚拟机中的ios文件,容器相当于虚拟机系统,仓库相当于系统中的进程或者执行文件,容器是通过镜像创建的 1.镜像 Docker 镜像就是一个 Linux 的文件系统&#xff08; Root FileSystem &#xff09;&#xff0c;这个文…

万宾科技智能井盖传感器怎么使用?

时代在进步&#xff0c;科技在更新&#xff0c;人们身边的万事万物都在随着时代的脚步不断的前进。各种各样高科技技术在城市基础设施建设的过程中得到应用&#xff0c;很多智能产品不仅施工方便&#xff0c;而且可以向政府部门提供精准的数据&#xff0c;提高了相关管理人员的…

一、PHP环境搭建[phpstorm]

一、安装 1.php编写工具 地址&#xff1a;https://www.jetbrains.com/phpstorm/download/#sectionwindows 图示&#xff1a; 2.php环境 解释&#xff1a;建议使用phpstudy进行安装&#xff0c;安装较为简单 链接&#xff1a;https://www.xp.cn/ 图示&#xff1a; 二、第…

leetcode系列(双语)002——GO两数相加

文章目录 两数相加 | Add Two Numbers示例个人解答官方解答扩展Algorithm 两数相加 | Add Two Numbers You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order, and each of their nodes contains a sing…

yyds,Elasticsearch Template自动化管理新索引创建

一、什么是Elasticsearch Template&#xff1f; Elasticsearch Template是一种将预定义模板应用于新索引的功能。在索引创建时&#xff0c;它可以自动为新索引应用已定义的模板。Template功能可用于定义索引的映射、设置和别名等。它是一种自动化管理索引创建的方式&#xff0…

Elasticsearch:使用 Open AI 和 Langchain 的 RAG - Retrieval Augmented Generation (四)

这篇博客是之前文章&#xff1a; Elasticsearch&#xff1a;使用 Open AI 和 Langchain 的 RAG - Retrieval Augmented Generation &#xff08;一&#xff09;Elasticsearch&#xff1a;使用 Open AI 和 Langchain 的 RAG - Retrieval Augmented Generation &#xff08;二&a…

SQL实现数据透视效果

一、透视 在SQL中实现类似Excel中数据透视表的效果&#xff0c;需要使用到PiVOT函数 SELECT <non-pivoted column>,[first pivoted column] AS <column name>,[second pivoted column] AS <column name>,... FROM(<SELECT query that produces the data…

0基础学习PyFlink——不可以用UDTAF装饰器装饰function的原因分析

在研究Flink的“用户自定义方法”&#xff08;UserDefinedFunction&#xff09;时&#xff0c;我们看到存在如下几种类型的装饰器&#xff1a; UDF&#xff1a;User Defined Scalar FunctionUDTF&#xff1a;User Defined Table FunctionUDAF&#xff1a;User Defined Aggrega…

doris 问题 列表

1. flink 导入数据后 出现的错误 2.错误描述&#xff1a; 导入任务过多&#xff0c;新导入任务提交报错 “current running txns on db xxx is xx, larger than limit xx ”&#xff1f; 调整 fe 参数 : max_running_txn_num_per_db&#xff0c;默认100&#xff0c;可适当调…

vue3 elementPlus 表格实现行列拖拽及列检索功能

1、安装vuedraggable npm i -S vuedraggablenext 2、完整代码 <template> <div classcontainer><div class"dragbox"><el-table row-key"id" :data"tableData" :border"true"><el-table-columnv-for"…

ChatGPT和Copilot协助Vue火速搭建博客网站

AI 对于开发人员的核心价值 网上会看到很多 AI 的应用介绍或者教程 使用 AI 聊天&#xff0c;咨询问题 —— 代替搜索引擎使用 AI 写各种的电商文案&#xff08;淘宝、小红书&#xff09;使用 AI 做一个聊天机器人 —— 这最多算猎奇、业余爱好、或者搞个套壳产品来收费 以上…