多线程环境下还敢用System.out.println?坑!

背景

一个文件采集系统,使用了多线程递归采集指定目录下的文件,并为每个目录创建一个线程去采集。

这个应用每隔几天就出现罢工情况,查看进程还在,堆内存空间还很充足,就是导出堆栈时,发现所有的采集线程都处于 BLOCKED 状态了:

bash 复制代码
"thread/dir/1718963987160" #82581 prio=5 os_prio=0 tid=0x00007f498c109000 nid=0x3d359a waiting for monitor entry [0x00007f48fcdfe000]
   java.lang.Thread.State: BLOCKED (on object monitor)
	at java.io.PrintStream.println(PrintStream.java:805)
	- waiting to lock <0x00000005cf055888> (a java.io.PrintStream)
	at com.xxx.XXX.sortFile(XXX.java:553)
...

下图是某次堆栈的内容,采集子目录过多时,创建的 292 个采集线程全阻塞了:

问题定位

定位到这个采集类的 sortFile 函数,里面第一行就是 System.out.println(dir) 打印当前处理的目录名称,在采集目录层级过多时,采集任务的线程达到了292 个,最终导致了线程阻塞。

为什么 System.out.println 会导致阻塞呢?

启示录

又想吐槽祖传代码了!生产环境里面大量的 System.out.println 真的是无语了。生产环境下,日志配置的 Logger 只是 FileLogger,控制台日志不会输出。这些控制台打印就成了影响程序性能的蛀虫,一不留神,还会造成本文介绍的死锁阻塞情况,直接拖挂了应用。

有点想念我刚入行时的那家企业,它是一家金融软件外包企业,虽说是外包,但当时行方对代码质量的严格要求,至今仍令我印象深刻,使用 findBugs 扫描出来的任何问题,包括警告都必须解决掉,否则行方就不允许上线。

从那儿学到的代码质量意识到现在还获益匪浅,之后就没有碰到过注重代码质量的企业了。

再总结一下简单的编码规范:

  1. 生产环境禁止 System.out.println 和 console 日志输出,前者存在本文的风险,后者会造成日志重复生产,引发磁盘空间的浪费,。
  2. 生产环境只允许一个 main 入口函数,其他所有测试的 main 函数必须删除,否则就容易成为后门。
相关推荐
Joey_friends15 小时前
指纹authenticate流程图
android·java·c++
一缕清烟在人间15 小时前
HarmonyOS应用开发实战:萌宠日记 - 生命周期在萌宠日记中的实践
后端
Conan在掘金15 小时前
鸿蒙 ArkUI 组件深水区:Span 富文本嵌套,一行 Text 塞下「红蓝斜下大」五样式 + 动态高亮
后端
卷无止境15 小时前
Python 类型注解与运行时反射:从原理到工程实践
后端·python
郑州光合科技余经理15 小时前
家政O2O平台解析:从0搭建上门预约小程序解决方案
android·java·开发语言·前端·小程序·架构·php
耀耀_很无聊16 小时前
13_Spring Boot 3.5.8 + Redisson 3.45.1 导致 Sa-Token 登录 StackOverflowError
spring boot·后端·bootstrap
AskHarries16 小时前
邮件发送方案对比
后端
野蛮人6号16 小时前
黑马天机学堂系列问题之域名无法正常使用
java·spring cloud·天机学堂
学计算机的计算基16 小时前
回溯算法下篇:四道经典题讲透约束剪枝、原地标记、预计算与状态压缩
java·笔记·算法
Ai拆代码的曹操16 小时前
@Async 注解失效的底层真相:this 调用绕过代理,接口响应翻倍
后端