定义
在多线程情况下,如果一个线程拥有某个资源的锁,那么这个线程就可以运行资源相关的代码,其他线程就只能等待其执行完毕后,才能继续争夺资源锁,从而运行相关代码。
场景
车票售卖系统,当剩余车票为1张,此时有A/B/C/D四个用户同时来购票,系统开启了四个线程来执行业务操作。
上图中,
首先A线程刚执行了step1;
此时CPU将执行权切换到B线程,B线程顺利执行了step1和step2,此时余票数为0;
这时CPU将执行权又切换到了A,A线程继续执行step2,此时余票数变成了-1,出现了一场业务数据。
上述的情况就是多线程模式下的数据安全问题。
案例分析
某接口压测结果如下:
第一次压测:30线程5分钟
第二次压测:40线程跑5分钟
第三次压测:50线程跑5分钟
从上述3次测试结果来看,CPU利用率不变的情况下,线程增多,TPS不升反降。
重新跑一次50线程跑5分钟,脚本运行过程中获取线程信息:
1、通过jvisualvm查看线程,鲜红色代表阻塞,同时获取线程dump信息
2、直接在服务器上多执行几次jstack,将线程日志下载到本地后查询“BLOCKED”,找到问题代码
注:上述例子中log4j源码中加了锁,将日志级别调整到ERROR级别,重新压测,TPS提高,没有阻塞情况
总结
线程阻塞问题排查流程: 1、做线程dump 2、在dump文件中搜索关键字"BLOCKED"、"TIME_WAITTING",查看每种状态的count数量 3、按照上述关键字搜索,查看跟本系统有关的业务代码堆栈信息