半夜三更突然接到电话,部分用户无法登录成功进入服务,赶紧爬起来远程服务器看看是什么问题。最初以为是死锁,查了堆栈没发现问题。
反馈问题是部分用户,而用户访问这块之前是做了线程池分配固定线程处理,查了下日志,发现这些用户确实都是分配到同一条线程,那问题基本确定是线程挂了或者死循环了。top一下发现cpu果然异常的高,就排查下占用cpu最高的线程(top -H -p pid(cpu高的进程pid)获得cpu占用高的线程pid假设为9564,然后转换一下printf %x 9564 得到其16进制值 255c),再jstack -l pid | grep '255c' -A10 就获取到死循环线程相关的信息了(此处pid为进程pid)。看到线程最后执行是一处使用TreeSet对象进行排序处理的地方,跑进了TreeMap的fixAfterDeletion方法,进去一看是while循环处理,那应该就是这里出问题了。
查了下资料,就是因为TreeMap本身并非线程安全,所以在多线程并发环境下可能就会出现死循环,,TreeSet和TreeMap必须做好同步处理,可以用Collections的辅助api来加上同步保护,如:synchronizedSortedSet。