cache線程池對數據庫操做的飢餓問題

最近的工做中,由於程序須要大量進行數據庫查詢,我使用ArrayBlockingQueue模仿數據庫鏈接池,裏面初始化了固定數量的數據庫鏈接對象。數據庫

個人業務中,存在主任務生成子任務,而後經過Future對象等待子任務返回結果的狀況,爲了不已經在work隊列的主任務一直佔着cpu等待子任務返回,而子任務因爲在task隊列中,所以得不到cpu資源,沒法執行。我使用了cache線程池,讓全部任務都能被封裝爲thread,能夠獲得cpu時間。測試

這個設計在測試環境的小數據集下運行是正常的,任務都能執行完,但提交到生產環境,就會在運行一段時候後出問題,現象是程序日誌中止,對象gc也中止,彷佛程序中止或者在被阻塞住了。線程

後來經過jstack命令,將程序的線程調用棧幀拿來分析發現大量的線程是處於packing狀態,並且他們都是在ArrayBlockingQueue的take()方法上阻塞,數量有436個。設計

所以懷疑,多是有方法將A鏈接池中的dbHelper用完後,放到了B鏈接池中,致使最後A鏈接池中dbHelper所有泄露到了其餘地方,所以沒有線程能再獲取到數據庫鏈接。但對代碼檢查後,沒有發現這種問題。日誌

接下來再看線程棧幀,發現線程cache線程池的線程id已經到了893,證實cache線程池中有大量線程生產,這些線程都處於packing狀態。只有一個線程是runnable狀態,他得到了dbHelper,正在查詢數據庫。對象

因而我懷疑,是由於生成了大量線程,這些線程都須要分配cpu時間才能執行,但每一個線程都只能分配到不多的cpu時間,致使持有dbHelper的線程遲遲執行不完,它沒法釋放dbHelper,其餘線程也只能浪費着cpu時間等着。隊列

接下來修改代碼,主任務仍是在cache線程池中,但其產生的子任務,放到另一個fix線程池中執行,這樣cpu就會將fix的worker隊列中的查詢先執行完,將dbHelper還回鏈接池,再去執行新的子任務,而不會建立過多的thread去等待dbHelper。修改完成後,從新執行程序,終於在日誌中發現了新的日誌,問題被解決。資源

其實到最後,我也不知道本身的分析是否徹底正確。thread

相關文章
相關標籤/搜索