2018-01-04 15:02:03,319 ---com.mchange.v2.async.ThreadPoolAsynchronousRunner: com.mchange.v2.async.ThreadPoolAsynchronousRunner$DeadlockDetector@4d6c4ebb -- APPARENT DEADLOCK!!! Creating emergency threads for unassigned pending tasks!
先說說APPARENT DEADLOCK!!!什么情況下會拋出這樣的異常?
通過看源碼,源碼是個好東西,有個檢測死鎖的DeadlockDetector,每隔一段時間就會檢測一次,是一個TimerTask,里面是這樣寫的:
current = (LinkedList) pendingTasks.clone();
if ( current.equals( last ) ){
logger.warning(this + " -- APPARENT DEADLOCK!!! Creating emergency threads for unassigned pending tasks!");
}
解釋一下current和last
代碼里這兩個對象分別是一個LinkedList
current用來記錄當前等待獲取連接的AcquireTask
last用來記錄上次等待獲取連接的AcquireTask
如果二者相等的話,C3P0認為是死鎖,拋出警告
什么情況下會出現這樣的異常?
1.數據庫連接不上的話,會報這樣的異常,檢查數據源配置是否正確?
我在本地測試,沒有配置checkoutTime(獲取連接的超時時間)這個參數,20根線程並發發起連接,檢測死鎖的線程的線程,試想,在某次檢測過程中發現18個等待連接的任務,那么在下一次檢測的時候,這18個連接任務,仍舊沒有連上數據庫,可能是數據庫連接配置錯誤,檢查數據源配置信息,滿足出這個錯誤的條件,當然就會報APPARENT DEADLOCK!!!
2.在緩存中存在Statement,來說說這個
網上有人回答這個問題,說是設置c3p0.maxStatements=0,為啥設置一下這個就OK了呢?
這里說說我個人思考,因為在數據庫里的Statement的緩存都是在連接基礎上了,存在緩存了,這里我理解就是就是占用了數據庫的連接數,而申請新的連接的過程中,在達到連接數最大時,檢測死鎖的線程又可能會檢測出2次等待連接是AcquireTask相等,就會拋出異常。
My workaround:
In hibernate.cfg.xml:
In c3p0.properties:
c3p0.maxStatementsPerConnection=100
For such setting my multithreaded applications runs with no APPARENT DEADLOCK error (finally and ... hopefully that this problem is really solved).
My app running quite fast so I guess (and I believe) that Statement caching is working. Statements caching is crucial for me because of performance. In other words I couldn't just turn Statement caching off (*).
As far as I can see turning Statement caching off (this global statement caching) is one (or maybe the only one) solution to get rid of APPARENT DEADLOCK errors.
Damn, I really would like to have time to have a look at c3p0 source code and figure out where is the reason of those fu!@#$% errors (Oracle JDBC or Hibernate or c3p0).
總結一下:就是用戶申請新的連接的時候,舊的連接又沒有及時釋放,那么就會拋出APPARENT DEADLOCK!!!的異常了。