對Java線程池使用的總結

    最近的項目中,遇到了一些須要頻繁使用sql查詢,寫入文件,能夠拆分子任務的狀況。爲了提升程序吞吐量,我使用了線程池。sql

    一開始,考慮將用戶按照數量進行分片,由於在數據庫查詢中,oracle對where in()有不得超過1000個查詢量的限制,因此考慮將每900個用戶分一片,每片爲一個task,交給fix線程池處理。數據庫

    可是每一個task又有查詢優惠券和查詢待評論數兩個較大的子任務,這兩個子任務須要大量的sql查詢,因而又考慮將這兩個子任務也封裝爲task,交給線程池處理。但由於主任務的執行依賴子任務的結果,若是使用同一個線程池,則子任務被提交後,work隊列中被執行的任務仍是主任務,cpu一直在先提交的主任務上等待Future.get()的返回,子任務得不到cpu資源去執行,一直在任務隊列中等待,這將形成程序的死等待。因此將線程池由fix改成cache,但願提交的任務能獲得cpu時間,不會一直在隊列中等待。後來這裏也引起了問題,將在下一篇文章中說明。網絡

   當用戶的帳單數據被計算出來後,須要調用模板中心生成郵件,還須要將生成的郵件保存到磁盤上,這是兩種不一樣的io密集型任務,一個是在socket上等待,一個是在本地io上等待。考慮到若是繼續提交到cache線程池,那麼線程池會爲每一個task生成一個線程,將耗費大量資源,cpu將頻繁切換線程,下降了程序的吞吐量。所以新建一個fix線程池,將這些後續任務提交給fix線程池處理,線程池使用固定數量的work去跑,即能在不一樣阻塞狀況下,讓程序能夠繼續運行,也避免了建立大量thread的資源浪費。oracle

    其實最後程序裏用了五個線程池,分級使用的緣由有如下考慮:socket

    爲了提升程序執行效率,能夠將用戶先按照語言分類,而後再按照900人一片進行分片,每片任務中,又涉及到兩個頻繁查詢數據庫的子任務,每片處理完後,又須要進行網絡io生產郵件和磁盤io保存郵件。若是用相同的線程池,則上級任務生產的子任務提交fix線程池後,由於work隊列還在被上級任務佔用,不一樣類型的io操做都將在task隊列中等待,沒法提升系統吞吐量。將下級任務提交到其餘線程池後,下級任務就能有當即執行的機會,進行網絡io和磁盤讀寫,提升了運行效率。線程

相關文章
相關標籤/搜索