1

我正嘗試使用ExecutorService線程池在Java中創建多線程應用程序。該應用程序基本上查詢第三方服務的關於給定關鍵字的數據。由於我有很多關鍵字,每個請求都需要一些時間來生成,所以我想要並行查詢服務。這些請求是通過ServiceHandler對象完成的,該對象負責認證並解析結果。在線程池中的任務之間但不是在Java線程之間共享對象

在我最初的實現中,我爲每個關鍵字創建一個新的Callable,並創建一個新的ServiceHandler對象來查詢服務。由於某些原因,這比在所有Callable上共享一個單例ServiceHandler對象的速度更快。但是,對於大量輸入數據集,我遇到了內存問題,因爲它爲每個輸入關鍵字創建新對象。

有沒有辦法仍然使用ExecutorService,但只爲每個工作線程創建一個不同的ServiceHandler實例?例如,如果我有1000個關鍵字和20個線程的固定池,我只想爲每個線程創建一個ServiceHandler(共20個),同時每個關鍵字仍然有一個Callable(總計1000個)。

我試圖向每個在其initialValue()中返回一個新的ServiceHandler的Callable對象添加一個靜態的ThreadLocal對象,但是似乎只有一個ServiceHandler正在創建?我可以發佈我的代碼,但我甚至不確定這是否是正確的方法。

回答

1

是的,有一種方法只能爲每個線程創建一個對象實例,您應該使用ThreadLocal<ServiceHandler>並將其聲明爲靜態字段。這將只爲每個線程創建一個對象實例。 您可以檢查http://docs.oracle.com/javase/6/docs/api/java/lang/ThreadLocal.html這是官方文檔。

+0

我試過了,並在ServiceHandler中添加了一個新的static volatile instanceCount變量。當我在ServiceHandler的構造函數中增加該變量並將其打印出來時,我總是得到1,這看起來像我只創建一個實例? – Yiling

0

我認爲這是一個生產者 - 消費者問題。您擁有一個BlockingQueue,它可以包含儘可能多的關鍵字以及20個消費者/服務線程池。

服務線程的工作是這樣的:

while (true) { 
    Keyword k = queue.pop(); 
    process(k); 
} 

您的生產者線程只是填補了隊列中要處理和服務的一個線程會照顧它的關鍵字。

+0

它基本上是,但我想使用ExecutorService,因爲它允許我創建一個讀取輸入的主類,創建線程池,然後在從服務返回結果後寫出輸出。如果我創建單獨的服務線程,我必須實現我自己的ExecutorService類型框架。 – Yiling

0

我弄清楚我的特殊問題是什麼。正確的解決方案是使用ThreadLocal對象,但是我的實現問題是我在構造每個Callable時調用ThreadLocal.get()方法。由於構造是在主線程中進行的,而不是在ExecutorService的工作線程中進行的,所以我總是得到相同的ServiceHandler實例,這使得它的執行類似於單例。

一旦我將調用get()移動到Callable的call()方法,就會發生正確的執行。

+0

所以現在您可以將其中一個答案標記爲正確 – Desert

相關問題