首页 > 编程语言 >震惊,程序运行一半就不运行了

震惊,程序运行一半就不运行了

时间:2024-07-05 12:52:18浏览次数:16  
标签:method2 自定义 程序运行 method1 一半 代码 线程 Async 震惊

近期,我们的项目在生产环境中运行时频繁出现一个难以理解的Bug。这个问题颇为有趣,因此我决定在此记录下整个排查过程。

首先,让我模拟一下出问题的代码:

XController.java

@Resource
private XService xService;

@GetMapping("/method1")
public void method1(){
System.out.println("a");
xService.method2();
}

 

XService.java

@Async
public void method2() {
System.out.println("b");
}

  

如上代码所示,逻辑相当简单。在Controller中的`method1`里,我们首先打印一个“a”,然后调用Service的`method2`,在`method2`中打印一个“b”。按照常理,每次调用`method1`都应该依次打印“a”和“b”。大多数人可能都会这样认为,也确信结果必然如此。然而,事实却是有时只打印了“a”,而没有打印“b”,并且没有任何异常日志。

这个现象超出了我们的认知,一时间让人感到困惑。程序为何运行一半就停止了?难道多年的认知要被推翻,全世界都错了吗?

仔细思考后,作为一个拥有多年CRUD经验的程序员,我认为问题应该还是出在我自己身上。那么,问题究竟在哪里呢?

通过对比常规代码与这段代码的区别,我发现这段代码唯一特殊的地方在于使用了`@Async`注解。另外,这部分代码近期才开始显现出问题,难道是其他地方的改动影响到了这里?

有两个排查方向:一是调查`@Async`的使用情况;二是检查近期的代码更改。

众所周知,`@Async`的作用是让系统在新的线程中执行`method2`。但为什么有时不执行呢?难道是系统没有开启新线程?或者是线程不够用了?通常情况下,`@Async`使用的是Spring默认的线程池,而这个线程池的大小几乎是无限的。我们系统的访问量并未达到这个级别。

会不会是`@Async`使用了其他的线程池?为了核实这一点,我查看了日志文件,发现在打印“a”的那行日志前面有线程名“myThread-1”。这个线程名显然是自定义的,并非Spring自带的。

进一步在代码中全局搜索“myThread”关键字,果然发现了自定义线程池的地方。经过检查代码提交记录,确认是其他同事最近提交的代码引起的问题。

再来看自定义线程池的配置:

 

executor.setMaxPoolSize(1);
executor.setQueueCapacity(50);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());

  

线程池中只有一个线程,队列容量为50。这意味着同时只能有50个任务排队等待执行。拒绝策略采用了`DiscardPolicy`,该策略会在队列已满时直接抛弃新任务,且不抛出异常。

复盘系统实际运行过程:当`method1`执行到`method2`时,会使用自定义线程池中的唯一一个线程`myThread-1`来执行。如果`myThread-1`已有任务在执行,新任务会进入队列排队。若任务过多超过50个,新任务就会被抛弃,不再执行。

由于任务被抛弃,这就解释了为何没有打印“b”。同时,由于采用了`DiscardPolicy`策略,因此没有异常日志产生。

知道了问题的原因,解决方案就变得清晰了。有两种解决方法:
1. 移除自定义线程池,回归使用默认线程池(尽管默认线程池存在无限队列问题,但我们的项目负载不会那么大)。
2. 调整自定义线程池的配置,增加线程数至8,队列容量扩大到几千,并将拒绝策略改为抛出异常的策略。

标签:method2,自定义,程序运行,method1,一半,代码,线程,Async,震惊
From: https://www.cnblogs.com/hichanglong/p/18285588

相关文章

  • 震惊:全面拆解dapp上线三天、 规则漏洞导致资金全部损失
    背景:今天的分析的是链上一个土狗项目由于规则设计漏洞、导致被黑客利用漏洞攻击、致使资金全部损失的案例、近期这个项目也是圈内很火、今天看到了,就趁周末有时间从技术的角度,分析黑客如何利用链上部署的合约,进而干废项目方。今天说的这个,不是技术漏洞bug、是规则设计漏洞......
  • 震惊!不掺杂一点水分的docker harbor搭建干货!
    生产环境dockerharbor搭建环境已包含docker和docker-compose下载dockerharbor下载地址:https://github.com/goharbor/harbor/releases/修改配置文件并安装root@harbor:/opt#tarzxfharbor-online-installer-v2.10.2.tgzroot@harbor:/opt#cdharbor/root@harbo......
  • 出现次数超过一半的数
    题目描述输入n个大小在[-50,50]的数,n<=1000,你需要找出出现次数超过一半的数,例如现在有7个数,大小分别为3,5,3,4,3,3,2,数字3的出现次数就超过一半了。当然有可能不不存在这样的数。输入格式第一行一个整数n,表示数的个数。第二行n个整数,每个整数的大小在[-50,50]范围......
  • 震惊 vue+express创建的node上线竟然如此简单!
    1去阿里云申请服务器   首先登录阿里云,搜索服务器esc选择免费试用选择centos选择一台服务器   然后进入服务器控制台,点击概况选择重置密码修改root用户密码用户名为root不建议修改   点击远程连接输入自己的密码   输入命令安装宝塔面板 ......
  • cmd-字(一半)
    #include<bits/stdc++.h>#include<windows.h>#include<conio.h>//控制台输入输出文件usingnamespacestd;intmain(){HANDLEhandle=GetStdHandle(STD_OUTPUT_HANDLE);//获取标准输出的句柄COORDcoord={15,5};//保存光标坐标COORDcoord1={22,5}......
  • 【ubuntu】程序运行时的任务栏图标
    1.快捷方式需要正确的配置StartupWMClass属性,那么如何获取这个属性呢?参考如下命令xprop|grepWM_CLASS将终端程序小窗运行上述命令,鼠标点击哪个应用窗体就会获取哪个窗体的名称,有可能会有多个,多个情况任选其一2.将图标复制到 /usr/share/pixmaps/中,文心一言的问答提到......
  • FLINKCDC3.0 datastream程序运行测试
    1.编写程序本地运行正常2.程序正常打包3.提交作业到FLINK集群./bin/flinkrun-mhdf1:8081-ccom.org.cdc.FlinkCDCDataStreamTest./FlinkCdc-test.jar4.监控作业运行作业正常运行,cud查看taskmanagerlog,可以看到cud变更数据5.给当前的Flink程序创建Savepointbin/flin......
  • 2024-05-01:用go语言,给定两个长度为偶数n的整数数组nums1和nums2, 分别移除它们各自的一
    2024-05-01:用go语言,给定两个长度为偶数n的整数数组nums1和nums2,分别移除它们各自的一半元素,将剩下的元素合并成集合s。找出集合s中可能包含的最多元素数量。输入:nums1=[1,2,3,4,5,6],nums2=[2,3,2,3,2,3]。输出:5。答案2024-05-01:chatgpt题目来自leetcode3002。大体......
  • 默认显示三张,第一张和第三张只显示一半,中间全部显示,点击可左右切换默认显示一二张
     项目地址:https://github.com/holiday0912/SwiperPreView   varswiper=newSwiper(".swiper-container",{autoplay:false,loop:true,initialSlide:2,spaceBetween:20,centeredSlides:true,slidesPerView:1.9,p......
  • GO 语言编写的程序运行过程详解
    1.1go源代码packagemainfuncmain(){goadd(1,2)}funcadd(a,bint)(int,int,int){returna+b,a,b}1234567先来看看上面这段程序的反汇编代码:1.2add函数反汇编代码0x401050  48c744241800000000  MOVQ$0x0,0x18(SP)0x401059  48c744......