原文html
在 jstack
的內容中能夠看到如下的 MySQL Statement Cancellation Timer
守護線程, 在業務高峯期的時候會出現大量的這類守護線程, 由此追溯該線程的生命週期過程;java
"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
java.util.TimerThread
是 Timer.java
文件裏的一個內部類, 主要負責 Timer
隊列任務的執行和調度;mysql
Timer.java:526
位置的代碼, 當前狀態 WAITING (on object monitor)
, 表示當前的 timer
線程池爲空, 正在等待新入駐;Timer.java:552
位置的代碼, 當前狀態 TIMED_WAITING (on object monitor)
表示任務等待被激活;根據線程名稱 MySQL Statement Cancellation Timer
繼續追溯, 在 com.mysql.jdbc.ConnectionImpl#getCancelTimer
方法中找到該 TimerThread
的建立(cancelTimer
):sql
主要是 mysql-connector-java-xxx.jar
中負責 sql 查詢的 Statement
數據庫
在 com.mysql.jdbc.StatementImpl#executeQuery
方法中能夠發現, 當啓用 queryTimeout
且 timeoutInMillis!=0
時, 在執行 sql 的時候就會建立一個 CancelTask
的線程來控制超時; (後面那個 versionMeetsMinimum
是個版本判斷能夠先忽略)segmentfault
而後在項目的 application.yml
中發現配置 mybatis.configuration.default-statement-timeout: 5
, 因此 mybatis
在每次的數據庫查詢都會加上 queryTimeout
, 且該配置對全局 SQL 生效, 包括 insert
, select
, update
;mybatis
在 com.mysql.jdbc.StatementImpl.CancelTask#run
方法中, 會另起一個線程, 判斷若是啓用了 queryTimeoutKillsConnection
的配置時, 會調用當前 Statement
對應的 Connection
裏的 realClose
方法;app
在 realClose
方法裏發現會關閉 cancelTimer
線程;oop
在 com.mysql.jdbc.ConnectionImpl#close
方法裏也會發現有 realClose
方法的調用, 即在鏈接關閉時也會處理 cancelTimer
的釋放優化
設置了 queryTimeout
會使 jdbc driver
在每次查詢數據庫時新建 CancelTask
(timeoutTask
對象) 線程來處理超時, 並使用 CancelTimer
(在 ConnectionImpl
類中) 來進行調度;
若是 SQL
查詢超時了, 則會在 timeoutTask
的 run
方法裏調用 com.mysql.jdbc.ConnectionImpl#realClose
來釋放 CancelTimer
;
若是 Connection
正常關閉 close
時, 也會調用 com.mysql.jdbc.ConnectionImpl#realClose
來釋放 CancelTimer
;