追溯 MySQL Statement Cancellation Timer

在 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.TimerThread 是 Timer.java 文件里的一个内部类, 主要负责 Timer 队列任务的执行和调度;

追溯 MySQL Statement Cancellation Timer

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

根据定位 Timer.java:552 位置的代码, 当前状态 TIMED_WAITING (on object monitor) 表示任务等待被激活;

追溯 MySQL Statement Cancellation Timer

3. getCancelTimer

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

追溯 MySQL Statement Cancellation Timer

4. getCancelTimer 的上游调用

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

追溯 MySQL Statement Cancellation Timer

追溯 MySQL Statement Cancellation Timer

5. 创建 CancelTask timeoutTask

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

追溯 MySQL Statement Cancellation Timer

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

追溯 MySQL Statement Cancellation Timer

6. CancelTask 执行过程

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

追溯 MySQL Statement Cancellation Timer

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

追溯 MySQL Statement Cancellation Timer

7. Connection 关闭时

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

追溯 MySQL Statement Cancellation Timer

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

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpssgx.html