最近在做一个子系统,大概的功能就是:
使用定时任务去检测很多数据,每次检测到数据不再指定范围内的时候,会输出日志System.out.print()并且调用新增数据的方法,在数据库中插入一条数据并且调用钉钉的信息提醒功能。
经过测试发现了一个问题,就是这个新增的方法是每次都能够调用成功的,而我的钉钉消息推送业务在新增的方法之后,这个业务却只调用了一次? 为了清楚明了,我是用System.out.print()在控制台进行打印日志来看程序是否执行了这个地方的代码。
当我再次测试的时候,发现仍然有这个问题,输出的日志System.out.print()里面的内容好像和随机的一样,有时候会输出,有时候不输出。于是我打断点进行调试,发现并没有什么问题,跟着断点就会一步一步执行。就离谱
于是我重新测试,发现还是该输出的日志没有输出。这也导致每次调用钉钉的业务消息就是随机的,偶尔成功偶尔不成功。
最初我考虑的原因是因为,在同一时间检测产生的数据量过大的问题?于是我给新增和业务的方法加上多线程,使用多个线程去处理,结果发现还是同样的问题,偶尔成功偶尔不行,这就很气,关键你一步步调试还没问题。
后来加上synchronize锁仍然不管用,气得睡不着觉~
第二天八点就到公司,今天不把他拿下我就不回去了,查了很多资料,发现有可能是System.out.print()的问题,我还在想一个输出语句还能有什么问题。
翻遍了小破站发现问题:
1、sop将产生大量的IO操作,比较耗性能,同时它是同步请求,如果没有打印的话,就不会往下走;相比而言,log是异步的,不会影响程序的其他操作,而且log可以将日志以文件的形式保存,这便于运维。
2、在生产环境中,根本就没有控制台让你看信息,所以sop就显得多余。
总结下:
打开println的源码,看到println方法体中有synchronized,也就是有锁的控制,换而言之就会出现阻塞的可能,后面我们会认为制造阻塞来演示。
如下图:
通过上个图,我们可以想到有这么一种场景,在System.out.println()运行过程中,或因系统原因或者其它原因,导致在执行println的时候,发生了阻塞,那么因此带来的后果是,所有使用System.out.println()的地方,都会处于block状态,甚至引发系统宕机等。
至于System.out.println()本身的性能问题,可以作为单纯的性能优化来讲,也是不建议使用,既然是深入分析,我们先看下严重的场景,这才是导致禁用Syste.out.println()的重要原因。
最终换成@Log4j2,使用log打印日志,问题解决。