并行运行测试时如何实现日志横幅仅在日志文件中输出一次
现有实现的问题
你当前的写法存在竞态条件漏洞,并非100%可靠:
- 多个并行线程可能同时判断
!isDone为true,在第一个线程修改isDone为true之前,多个线程都能进入判断块,即便doOnlyOnce加了synchronized修饰,也只会让这些线程串行执行方法,还是会出现横幅多次打印的问题,你当前没有复现只是偶发情况。 - 你把修改
isDone的操作放在了doOnlyOnce调用之前,还会出现标记已经设为true,但横幅还没打印完成的问题,不符合预期执行顺序。
优化后的可靠实现
可以用标准的双重检查锁定模式保证逻辑仅执行一次,同时兼顾并发性能:
class Foo { private static volatile Boolean isDone = false; // 单独的锁对象,避免锁范围扩散 private static final Object LOCK = new Object(); public Foo() { // 第一层无锁检查,高并发场景下性能更好 if (!isDone) { // 加类级锁,保证同一时间只有一个线程进入同步块 synchronized (LOCK) { // 第二层校验,避免多个线程等待锁后重复执行逻辑 if (!isDone) { // 先执行打印逻辑,完成后再修改标记 doOnlyOnce(); isDone = true; } } } } private void doOnlyOnce() { // 打印日志横幅的具体逻辑 } }
适配Log4j2的原生方案
针对你当前的技术栈,其实不需要自己实现同步逻辑,直接利用Log4j2的生命周期回调就能实现横幅仅打印一次:
自定义实现Log4j2的LoggerContextListener接口,重写contextStarted方法写入横幅逻辑,再将监听器注册到Log4j2配置中。LoggerContext全局仅会初始化一次,天然避免并行执行重复打印的问题,不需要额外加锁,性能和可靠性更高。
内容的提问来源于stack exchange,提问作者Brazen
相关产品推荐
相关产品推荐

