原文

1. 背景

jstack 的内容中可以看到以下的 MySQL Statement Cancellation Timer 守护线程, 在业务高峰期的时候会出现大量的这类守护线程, 由此追溯该线程的生命周期过程;

"MySQL Statement Cancellation Timer" #20647 daemon prio=5 os_prio=0 tid=0x00007f2d087e9800 nid=0xfb83 in Object.wait() [0x00007f2b4b45a000]
java.lang.Thread.State: TIMED_WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
at java.util.TimerThread.mainLoop(Timer.java:552)
- locked <0x00000005da147038> (a java.util.TaskQueue)
at java.util.TimerThread.run(Timer.java:505) Locked ownable synchronizers:
- None "MySQL Statement Cancellation Timer" #24138 daemon prio=5 os_prio=0 tid=0x00007f402802c800 nid=0x4cf64 in Object.wait() [0x00007f3e49453000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:502)
at java.util.TimerThread.mainLoop(Timer.java:526)
- locked <0x00000005f606cc60> (a java.util.TaskQueue)
at java.util.TimerThread.run(Timer.java:505) Locked ownable synchronizers:
- None

2. TimerThread

java.util.TimerThreadTimer.java 文件里的一个内部类, 主要负责 Timer 队列任务的执行和调度;

  • 根据定位 Timer.java:526 位置的代码, 当前状态 WAITING (on object monitor), 表示当前的 timer 线程池为空, 正在等待新入驻;
  • 根据定位 Timer.java:552 位置的代码, 当前状态 TIMED_WAITING (on object monitor) 表示任务等待被激活;

3. getCancelTimer

根据线程名称 MySQL Statement Cancellation Timer 继续追溯, 在 com.mysql.jdbc.ConnectionImpl#getCancelTimer 方法中找到该 TimerThread 的创建(cancelTimer):

4. getCancelTimer 的上游调用

主要是 mysql-connector-java-xxx.jar 中负责 sql 查询的 Statement

5. 创建 CancelTask timeoutTask

com.mysql.jdbc.StatementImpl#executeQuery 方法中可以发现, 当启用 queryTimeouttimeoutInMillis!=0 时, 在执行 sql 的时候就会创建一个 CancelTask 的线程来控制超时; (后面那个 versionMeetsMinimum 是个版本判断可以先忽略)

然后在项目的 application.yml 中发现配置 mybatis.configuration.default-statement-timeout: 5, 所以 mybatis 在每次的数据库查询都会加上 queryTimeout, 且该配置对全局 SQL 生效, 包括 insert, select, update;

6. CancelTask 执行过程

com.mysql.jdbc.StatementImpl.CancelTask#run 方法中, 会另起一个线程, 判断如果启用了 queryTimeoutKillsConnection 的配置时, 会调用当前 Statement 对应的 Connection 里的 realClose 方法;

realClose 方法里发现会关闭 cancelTimer 线程;

7. Connection 关闭时

com.mysql.jdbc.ConnectionImpl#close 方法里也会发现有 realClose 方法的调用, 即在连接关闭时也会处理 cancelTimer 的释放

8. 总结 MySQL Statement Cancellation Timer 线程的流程

设置了 queryTimeout 会使 jdbc driver 在每次查询数据库时新建 CancelTask(timeoutTask对象) 线程来处理超时, 并使用 CancelTimer(在 ConnectionImpl类中) 来进行调度;

如果 SQL 查询超时了, 则会在 timeoutTaskrun 方法里调用 com.mysql.jdbc.ConnectionImpl#realClose 来释放 CancelTimer;

如果 Connection 正常关闭 close 时, 也会调用 com.mysql.jdbc.ConnectionImpl#realClose 来释放 CancelTimer;

9. 阅读资料

  1. 一次数据库连接池优化的实践剖析
  2. MySQL Statement Cancellation Timer问题

最新文章

  1. 【菜鸟学习jquery源码】数据缓存与data()
  2. leetcode 日记 3sumclosest java
  3. table中的标题行冻结的简单实现
  4. Kali Linux Web 渗透测试— 第二十课-metasploit.meterpreter
  5. thinkphp 3.2.3+Admin LTE后台框架
  6. 2D客户端+微端技术总结
  7. Flex-Security权限控制框架
  8. IOS 学习参考
  9. [CSS]overflow内容溢出
  10. MapReduce输出格式
  11. 学习Emacs
  12. netty实现消息转发服务
  13. RabbitMQ-从基础到实战(1)— Hello RabbitMQ
  14. 对lea与mov的理解
  15. Lucene介绍与入门使用
  16. 论文笔记系列-Well Begun Is Half Done:Generating High-Quality Seeds for Automatic Image Dataset Construction from Web
  17. 短路运算符(逻辑与&amp;&amp; 和 逻辑或||)
  18. 配置selenium grid
  19. JS的防抖,节流,柯里化和反柯里化
  20. day1 计算机硬件基础

热门文章

  1. How many integers can you find HDU - 1796 容斥原理
  2. MIT 6.S081 聊聊xv6的文件系统(中)日志层与事务
  3. 生成不带签名(BOM)的UTF8格式的XML
  4. centos7+腾讯云服务器搭建wordpress
  5. Linux命令学习-01——find -type
  6. H.264视频压缩标准
  7. ASP.NET Core 中间件(Middleware)(一)
  8. Android四大组件简介:Android 基础知识,开发教程
  9. Objective C &amp; Swift &amp; iOS &amp; App
  10. chrome device remote debug