当前位置:首页 > 科技  > 软件

听我一句劝,业务代码中,别用多线程。

来源: 责编: 时间:2023-11-06 08:52:41 154观看
导读你好呀,我是歪歪。前几天我在网上冲浪,看到一个哥们在吐槽,说他工作三年多了,没使用过多线程。虽然八股文背的滚瓜烂熟,但是没有在实际开发过程中写的都是业务代码,没有使用过线程池,心里还是慌得一比。我只是微微一笑,这不是

你好呀,我是歪歪。nJp28资讯网——每日最新资讯28at.com

前几天我在网上冲浪,看到一个哥们在吐槽,说他工作三年多了,没使用过多线程。nJp28资讯网——每日最新资讯28at.com

虽然八股文背的滚瓜烂熟,但是没有在实际开发过程中写的都是业务代码,没有使用过线程池,心里还是慌得一比。nJp28资讯网——每日最新资讯28at.com

我只是微微一笑,这不是很正常吗?nJp28资讯网——每日最新资讯28at.com

业务代码中一般也使不上多线程,或者说,业务代码中不知不觉你以及在使用线程池了,你再 duang 的一下搞一个出来,反而容易出事。nJp28资讯网——每日最新资讯28at.com

所以提到线程池的时候,我个人的观点是必须把它吃得透透的,但是在业务代码中少用或者不用多线程。nJp28资讯网——每日最新资讯28at.com

关于这个观点,我给你盘一下。nJp28资讯网——每日最新资讯28at.com

Demo

首先我们还是花五分钟搭个 Demo 出来。nJp28资讯网——每日最新资讯28at.com

我手边刚好有一个之前搭的一个关于 Dubbo 的 Demo,消费者、生产者都有,我就直接拿来用了:nJp28资讯网——每日最新资讯28at.com

图片图片nJp28资讯网——每日最新资讯28at.com

这个 Demo 我也是跟着网上的 quick start 搞的:https://cn.dubbo.apache.org/zh-cn/overview/quickstart/java/spring-boot/nJp28资讯网——每日最新资讯28at.com

图片图片nJp28资讯网——每日最新资讯28at.com

可以说写的非常详细了,你就跟着官网的步骤一步步的搞就行了。nJp28资讯网——每日最新资讯28at.com

我这个 Demo 稍微不一样的是我在消费者模块里面搞了一个 Http 接口:nJp28资讯网——每日最新资讯28at.com

图片图片nJp28资讯网——每日最新资讯28at.com

在接口里面发起了 RPC 调用,模拟从前端页面发起请求的场景,更加符合我们的开发习惯。nJp28资讯网——每日最新资讯28at.com

而官方的示例中,是基于了 SpringBoot 的 CommandLineRunner 去发起调用:nJp28资讯网——每日最新资讯28at.com

图片图片nJp28资讯网——每日最新资讯28at.com

只是发起调用的方式不一样而已,其他没啥大区别。nJp28资讯网——每日最新资讯28at.com

需要说明的是,我只是手边刚好有一个 Dubbo 的 Demo,随手就拿来用了,但是本文想要表达的观点,和你使不使用 Dubbo 作为 RPC 框架,没有什么关系,道理是通用的。nJp28资讯网——每日最新资讯28at.com

上面这个 Demo 启动起来之后,通过 Http 接口发起一次调用,看到控制台服务提供方和服务消费方都有对应的日志输出,准备工作就算是齐活儿了:nJp28资讯网——每日最新资讯28at.com

图片图片nJp28资讯网——每日最新资讯28at.com

上菜

在上面的 Demo 中,这是消费者的代码:nJp28资讯网——每日最新资讯28at.com

图片图片nJp28资讯网——每日最新资讯28at.com

这是提供者的代码:nJp28资讯网——每日最新资讯28at.com

图片图片nJp28资讯网——每日最新资讯28at.com

整个调用链路非常的清晰:nJp28资讯网——每日最新资讯28at.com

图片图片nJp28资讯网——每日最新资讯28at.com

来,请你告诉我这里面有线程池吗?nJp28资讯网——每日最新资讯28at.com

没有!nJp28资讯网——每日最新资讯28at.com

是的,在日常的开发中,我就是写个接口给别人调用嘛,在我的接口里面并没有线程池相关的代码,只有 CRUD 相关的业务代码。nJp28资讯网——每日最新资讯28at.com

同时,在日常的开发中,我也经常调用别人提供给我的接口,也是一把梭,撸到底,根本就不会用到线程池。nJp28资讯网——每日最新资讯28at.com

所以,站在我,一个开发人员的角度,这个里面没有线程池。nJp28资讯网——每日最新资讯28at.com

合理,非常合理。nJp28资讯网——每日最新资讯28at.com

但是,当我们换个角度,再看看,它也是可以有的。nJp28资讯网——每日最新资讯28at.com

比如这样:nJp28资讯网——每日最新资讯28at.com

图片图片nJp28资讯网——每日最新资讯28at.com

反应过来没有?nJp28资讯网——每日最新资讯28at.com

我们发起一个 Http 调用,是由一个 web 容器来处理这个请求的,你甭管它是 Tomcat,还是 Jetty、Netty、Undertow 这些玩意,反正是个 web 容器在处理。nJp28资讯网——每日最新资讯28at.com

那你说,这个里面有线程池吗?nJp28资讯网——每日最新资讯28at.com

在方法入口处打个断点,这个 http-nio-8081-exec-1 不就是 Tomcat 容器线程池里面的一个线程吗:nJp28资讯网——每日最新资讯28at.com

图片图片nJp28资讯网——每日最新资讯28at.com

通过 dump 堆栈信息,过滤关键字可以看到这样的线程,在服务启动起来,啥也没干的情况下,一共有 10 个:nJp28资讯网——每日最新资讯28at.com

图片图片nJp28资讯网——每日最新资讯28at.com

朋友,这不就是线程池吗?nJp28资讯网——每日最新资讯28at.com

虽然不是你写的,但是你确实用了。nJp28资讯网——每日最新资讯28at.com

我写出来的这个 test 接口,就是会由 web 容器中的一个线程来进行调用。所以,站在 web 容器的角度,这里是有一个线程池的:nJp28资讯网——每日最新资讯28at.com

图片图片nJp28资讯网——每日最新资讯28at.com

同理,在 RPC 框架中,不管是消费方,还是服务提供方,也都存在着线程池。nJp28资讯网——每日最新资讯28at.com

比如 Dubbo 的线程池,你可以看一下官方的文档:nJp28资讯网——每日最新资讯28at.com

https://cn.dubbo.apache.org/zh-cn/overview/mannual/java-sdk/advanced-features-and-usage/performance/threading-model/nJp28资讯网——每日最新资讯28at.com

图片图片nJp28资讯网——每日最新资讯28at.com

而对于大多数的框架来说,它绝不可能只有一个线程池,为了做资源隔离,它会启用好几个线程池,达到线程池隔离,互不干扰的效果。nJp28资讯网——每日最新资讯28at.com

比如参与 Dubbo 一次调用的其实不仅一个线程池,至少还有 IO 线程池和业务线程池,它们各司其职:nJp28资讯网——每日最新资讯28at.com

图片图片nJp28资讯网——每日最新资讯28at.com

我们主要关注这个业务线程池。nJp28资讯网——每日最新资讯28at.com

反正站在 Dubbo 框架的角度,又可以补充一下这个图片了:nJp28资讯网——每日最新资讯28at.com

图片图片nJp28资讯网——每日最新资讯28at.com

那么问题来了,在当前的这个情况下?nJp28资讯网——每日最新资讯28at.com

当有人反馈:哎呀,这个服务吞吐量怎么上不去啊?nJp28资讯网——每日最新资讯28at.com

你怎么办?nJp28资讯网——每日最新资讯28at.com

你会 duang 的一下在业务逻辑里面加一个线程池吗?nJp28资讯网——每日最新资讯28at.com

图片图片nJp28资讯网——每日最新资讯28at.com

大哥,前面有个 web 容器的线程池,后面有个框架的线程池,两头不调整,你在中间加个线程池,加它有啥用啊?nJp28资讯网——每日最新资讯28at.com

web 容器,拿 Tomcat 来说,人家给你提供了线程池参数调整的相关配置,这么一大坨配置,你得用起来啊:nJp28资讯网——每日最新资讯28at.com

https://tomcat.apache.org/tomcat-9.0-doc/config/executor.htmlnJp28资讯网——每日最新资讯28at.com

图片图片nJp28资讯网——每日最新资讯28at.com

再比如 Dubbo 框架,都给你明说了,这些参数属于性能调优的范畴,感觉不对劲了,你先动手调调啊:nJp28资讯网——每日最新资讯28at.com

图片图片nJp28资讯网——每日最新资讯28at.com

你把这些参数调优弄好了,绝对比你直接怼个线程池在业务代码中,效果好的多。nJp28资讯网——每日最新资讯28at.com

甚至,你在业务代码中加入一个线程池之后,反而会被“反噬”。nJp28资讯网——每日最新资讯28at.com

比如,你 duang 的一下怼个线程池在这里,我们先只看 web 容器和业务代码对应的部分:nJp28资讯网——每日最新资讯28at.com

图片图片nJp28资讯网——每日最新资讯28at.com

由于你的业务代码中有线程池的存在,所以当接受到一个 web 请求之后,立马就把请求转发到了业务线程池中,由线程池中的线程来处理本次请求,从而释放了 web 请求对应的线程,该线程又可以里面去处理其他请求。nJp28资讯网——每日最新资讯28at.com

这样来看,你的吞吐量确实上去了。nJp28资讯网——每日最新资讯28at.com

在前端来看,非常的 nice,请求立马得到了响应。nJp28资讯网——每日最新资讯28at.com

但是,你考虑过下游吗?nJp28资讯网——每日最新资讯28at.com

你的吞吐量上涨了,下游同一时间处理的请求就变多了。如果下游跟不上处理,顶不住了,直接就是崩给你看怎么办?nJp28资讯网——每日最新资讯28at.com

图片图片nJp28资讯网——每日最新资讯28at.com

而且下游不只是你一个调用方,由于你调用的太猛,导致其他调用方的请求响应不过来,是会引起连锁反应的。nJp28资讯网——每日最新资讯28at.com

所以,这种场景下,为了异步怼个线程池放着,我觉得还不如用消息队列来实现异步化,顶天了也就是消息堆积嘛,总比服务崩了好,这样更加稳妥。nJp28资讯网——每日最新资讯28at.com

或者至少和下游勾兑一下,问问我们这边吞吐量上升,你们扛得住不。nJp28资讯网——每日最新资讯28at.com

有的小伙伴看到这里可能就会产生一个疑问了:歪师傅,你这个讲得怎么和我背的八股文不一样啊?nJp28资讯网——每日最新资讯28at.com

巧了,你背过的八股文我也背过,现在我们来温习一下我们背过的八股文。nJp28资讯网——每日最新资讯28at.com

什么时候使用线程池呢?nJp28资讯网——每日最新资讯28at.com

比如一个请求要经过若干个服务获取数据,且这些数据没有先后依赖,最终需要把这些数据组合起来,一并返回,这样经典的场景:nJp28资讯网——每日最新资讯28at.com

图片图片nJp28资讯网——每日最新资讯28at.com

用户点商品详情,你要等半天才展示给用户,那用户肯定骂骂咧咧的久走了。nJp28资讯网——每日最新资讯28at.com

这个时候,八股文上是怎么说的:用线程池来把串行的动作改成并行。nJp28资讯网——每日最新资讯28at.com

图片图片nJp28资讯网——每日最新资讯28at.com

这个场景也是增加了服务 A 的吞吐量,但是用线程池就是非常正确的,没有任何毛病。nJp28资讯网——每日最新资讯28at.com

但是你想想,我们最开始的这个案例,是这个场景吗?nJp28资讯网——每日最新资讯28at.com

图片图片nJp28资讯网——每日最新资讯28at.com

我们最开始的案例是想要在业务逻辑中增加一个线程池,对着一个下游服务就是一顿猛攻,不是所谓的串行改并行,而是用更多的线程,带来更多的串行。nJp28资讯网——每日最新资讯28at.com

这已经不是一个概念了。nJp28资讯网——每日最新资讯28at.com

还有一种场景下,使用线程池也是合理的。nJp28资讯网——每日最新资讯28at.com

比如你有一个定时任务,要从数据库中捞出状态为初始化的数据,然后去调用另外一个服务的接口查询数据的最终状态。nJp28资讯网——每日最新资讯28at.com

图片图片nJp28资讯网——每日最新资讯28at.com

如果你的业务代码是这样的:nJp28资讯网——每日最新资讯28at.com

//获取订单状态为初始化的数据(0:初始化 1:处理中 2:成功 3:失败)//select * from order where order_status=0;ArrayList initOrderInfoList = queryInitOrderInfoList();//循环处理这批数据for(OrderInfo orderInfo : initOrderInfoList){    //捕获异常以免一条数据错误导致循环结束    try{        //发起rpc调用        String orderStatus = queryOrderStatus(orderInfo.getOrderId);        //更新订单状态        updateOrderInfo(orderInfo.getOrderId,orderStatus);      } catch (Exception e){        //打印异常    }}

虽然你框架中使用了线程池,但是你就是在一个 for 循环中不停的去调用下游服务查询数据状态,是一条数据一条数据的进行处理,所以其实同一时间,只是使用了框架的线程池中的一个线程。nJp28资讯网——每日最新资讯28at.com

为了更加快速的处理完这批数据,这个时候,你就可以怼一个线程池放在 for 循环里面了:nJp28资讯网——每日最新资讯28at.com

//循环处理这批数据for(OrderInfo orderInfo : initOrderInfoList){    //使用线程池    executor.execute(() -> {        //捕获异常以免一条数据错误导致循环结束        try {            //发起rpc调用            String orderStatus = queryOrderStatus(orderInfo.getOrderId);            //更新订单状态            updateOrderInfo(orderInfo.getOrderId, orderStatus);        } catch (Exception e) {            //打印异常        }    });}

图片图片nJp28资讯网——每日最新资讯28at.com

需要注意的是,这个线程池的参数怎么去合理的设置,是需要考虑的事情。nJp28资讯网——每日最新资讯28at.com

同时这个线程池的定位,就类似于 web 容器线程池的定位。nJp28资讯网——每日最新资讯28at.com

或者这样对比起来看更加清晰一点:nJp28资讯网——每日最新资讯28at.com

图片图片nJp28资讯网——每日最新资讯28at.com

定时任务触发的时候,在发起远程接口调用之前,没有线程池,所以我们可以启用一个线程池来加快数据的处理。nJp28资讯网——每日最新资讯28at.com

而 Http 调用或者 RPC 调用,框架中本来就已经有一个线程池了,而且也给你提供了对应的性能调优参数配置,那么首先考虑的应该是把这个线程池充分利用起来。nJp28资讯网——每日最新资讯28at.com

如果仅仅是因为异步化之后可以提升服务响应速度,没有达到串行改并行的效果,那么我更加建议使用消息队列。nJp28资讯网——每日最新资讯28at.com

好了,本文的技术部分就到这里啦。nJp28资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-17156-0.html听我一句劝,业务代码中,别用多线程。

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 高性能Python开发:解密FastAPI的高并发秘籍!

下一篇: 聊聊Spring 微服务和多租户

标签:
  • 热门焦点
  • 小米官宣:2023年上半年出货量中国第一!

    小米官宣:2023年上半年出货量中国第一!

    今日早间,小米电视官方微博带来消息,称2023年小米电视上半年出货量达到了中国第一,同时还表示小米电视的巨屏风暴即将开始。“公布一个好消息2023年#小米电视上半年出货量中国
  • 2023 年的 Node.js 生态系统

    2023 年的 Node.js 生态系统

    随着技术的不断演进和创新,Node.js 在 2023 年达到了一个新的高度。Node.js 拥有一个庞大的生态系统,可以帮助开发人员更快地实现复杂的应用。本文就来看看 Node.js 最新的生
  • 一年经验在二线城市面试后端的经验分享

    一年经验在二线城市面试后端的经验分享

    忠告这篇文章只适合2年内工作经验、甚至没有工作经验的朋友阅读。如果你是2年以上工作经验,请果断划走,对你没啥帮助~主人公这篇文章内容来自 「升职加薪」星球星友 的投稿,坐
  • 电视息屏休眠仍有网络上传 爱奇艺被质疑“薅消费者羊毛”

    电视息屏休眠仍有网络上传 爱奇艺被质疑“薅消费者羊毛”

    记者丨宁晓敏 见习生丨汗青出品丨鳌头财经(theSankei) 前不久,爱奇艺发布了一份亮眼的一季报,不仅营收和会员营收创造历史最佳表现,其运营利润也连续6个月实现增长。自去年年初
  • 阿里大调整

    阿里大调整

    来源:产品刘有媒体报道称,近期淘宝天猫集团启动了近年来最大的人力制度改革,涉及员工绩效、层级体系等多个核心事项,目前已形成一个初步的“征求意见版”:1、取消P序列
  • 华为Mate60系列模具曝光:采用硕大圆形后置相机模组+拼接配色方案

    华为Mate60系列模具曝光:采用硕大圆形后置相机模组+拼接配色方案

    据此前多方爆料,今年华为将开始恢复一年双旗舰战略,除上半年推出的P60系列外,往年下半年的Mate系列也将迎来更新,有望在9-10月份带来全新的华为Mate60
  • 2纳米决战2025

    2纳米决战2025

    集微网报道 从三强争霸到四雄逐鹿,2nm的厮杀声已然隐约传来。无论是老牌劲旅台积电、三星,还是誓言重回先进制程领先地位的英特尔,甚至初成立不久的新
  • iQOO 11S新品发布会

    iQOO 11S新品发布会

    iQOO将在7月4日19:00举行新品发布会,推出杭州亚运会电竞赛事官方用机iQOO 11S。
  • Counterpoint :OPPO双旗舰战略全面落地 高端产品销量增长22%

    Counterpoint :OPPO双旗舰战略全面落地 高端产品销量增长22%

    2023年6月30日,全球行业分析机构Counterpoint Research发布的《中国智能手机高端市场白皮书》显示,中国智能手机品牌正在寻求高质量发展,中国高端智能
Top