调优过程
前提条件
- 服务器和操作系统正常运行。
- PC端已经安装SSH远程登录工具。
- 需要优化的Java程序。
操作步骤
- 进行在线分析。
在概览页签下观察每种状态的线程数量。
图1 概览1
发现有大量线程处于阻塞状态,有锁竞争的可能。
- 查看CPU页签的线程列表,执行多次线程转储操作。图2 线程转储
- 查看线程转储页签。图3 线程转储-线程概览
通过状态字段,筛选出阻塞状态的线程,点击Monitor详情,查看对应锁信息。
图4 线程转储
- 查看线程转储页签的Monitor详情。观察发现锁0x0000000101c98088,已被持有,有50个线程同时在竞争该锁。图5 Monitor详情
结合线程概览页面的栈信息,找到具体代码进行分析 。
图6 线程概览
发现使用的不是JUC提供的工具锁,程序中使用的是synchronized;如果锁竞争比较激烈,该类锁将升级成重量级,会导致上下文切换比较频繁,从而影响性能和关键业务的阻塞。
- 问题分析。
根据线程转储中提供的锁的类型和位置,咱们就可以分析代码的业务逻辑,从而找到调优方案。下面介绍两种锁竞争的调优方法,仅供参考。
- 情况一:使用synchronized,但在业务上竞争比较激烈。
将synchronized替换成JUC提供的工具锁(ReentrantLock等)。
- 情况二:使用JUC 提供的工具锁,但在业务上竞争比较激烈。
这种情况需要加入其他策略去提高性能,如加入线程池,限制竞争锁的线程数;如果是读写分离的场景,可以考虑使用ReadWriteLock,从业务的实际情况去考虑。
- 情况一:使用synchronized,但在业务上竞争比较激烈。
总结
Java中的锁竞争问题一旦发生很难定位具体的代码位置,因为程序干扰因素比较多,但是可以根据线程转储去定位,其中的栈信息提供了发生锁竞争的代码位置。
如果发现多个线程都试图锁住相同的锁地址,说明应用正面临锁竞争,在进行其他程序调优时,需要根据鲲鹏DevKit Java性能分析工具采集的实际结果和对应的优化建议进行调优操作,具体的调优思路可以参考本次实践。
父主题: 实践4:锁竞争定位调优实践