今天这个bug真的给我整破防了。下午三点接到一个线上告警某个接口偶尔返回500频率不高大概千分之几。看了下日志报错信息是NullPointerException堆栈指向一个工具类方法。第一反应这有啥难的加个判空不就完了。然后我就开始复现。本地跑没问题。压测环境跑没问题。测试环境跑还是没问题。行吧那就加日志呗。打了十几个log.info部署上去等。等了两个小时终于抓到一次。日志显示那个对象确实是null。但问题是——这个对象在方法入口明明是有值的中间经过了两层调用怎么就没了呢我开始逐行排查。看了半天突然注意到一个细节这个方法被一个Async注解的方法调用了。当时心里咯噔一下。因为那个对象是ThreadLocal里取的。Async会开新线程新线程拿不到主线程的ThreadLocal所以取出来就是null。就这么个玩意儿我折腾了快四个小时。说实话这种坑不是没踩过但每次踩到还是会觉得自己像个新手。你说这玩意儿它报错吧它也不报错就是偶尔返回个null你甚至不知道问题出在哪一层。后来我想了想其实根本原因就是我对这段代码的调用链路不够熟。那个Async是半年前另一个同事加的我当时review的时候压根没注意到它会影响ThreadLocal的传递。代码这种东西真的是你不动它它就不动你。但只要你碰了之前埋的雷就全炸了。最后改法也很简单把ThreadLocal的值在异步调用前取出来作为参数传进去不依赖线程上下文了。改完上线观察了一晚上没再出过。现在八点了我终于能睡了。写这篇东西也不是想教谁什么就是记录一下今天这个坑。以后要是再碰到类似的问题至少能少花两个小时。程序员嘛不就是在一个又一个坑里爬出来然后拍拍灰继续干。