2017-09-04 56 views
2

我需要在我的Spring應用程序中創建一個全局ThreadPoolTask​​Executor,它將負責在我的應用程序中運行多線程任務。Java中的受控ThreadPoolExecutor彈簧

但是,對於每個請求,我想限制從該全局ThreadPool使用的線程數。我應該如何確保根據請求執行此限制?

例如,

我創建一個全局線程池,最大池大小爲50個線程。但我想限制每個請求的線程數量來說5個線程。但是這5個線程只能從配置文件中定義的全局線程池中可用的50個線程中分配。

創建任務執行程序的配置類。

@Configuration 
public class ThreadPoolConfiguration { 

    @Value("${threadpool.corepoolsize}") 
    int corePoolSize; 

    @Value("${threadpool.maxpoolsize}") 
    int maxPoolSize; 

    @Bean 
    public ThreadPoolTaskExecutor taskExecutor() { 
     ThreadPoolTaskExecutor pool = new ThreadPoolTaskExecutor(); 
     pool.setCorePoolSize(corePoolSize); 
     pool.setMaxPoolSize(maxPoolSize); 
     pool.setWaitForTasksToCompleteOnShutdown(true); 
     return pool; 
    } 
} 

Controller類

@RestController 
public class WebController { 

    @Autowired 
    ThreadPoolTaskExecutor threadPool; 

    @RequestMapping("/process") 
    public String process(){ 

     String msg = ""; 
     List<Future<String>> futureList = new ArrayList<>(); 
     for(int threadNumber = 0; threadNumber < 5; threadNumber ++){ 
      CallableWorker callableTask = new CallableWorker(String.valueOf(threadNumber)); 
      Future<String> result = threadPool.submit(callableTask); 
      futureList.add(result); 
     } 

     for(Future<String> future: futureList){ 
      try { 
       msg += future.get() + "#####"; 
      } catch (Exception e){} 
     } 

     return msg; 
    } 
} 

免責聲明:這只是示例代碼,我從一個blog post了。

我該如何實現這樣的設計?我沒有看到任何可以創建的子線程池。我也不想爲每個請求實例化一個線程池,因爲這會是災難性的。

有什麼建議嗎?

+0

當一個請求有6個任務但僅限於5個線程時,你想要什麼樣的行爲?在排隊完成第6個任務之前,請等到前5個任務之一完成? –

+0

是的,完全一樣。但是,如果另一個請求帶有5個任務,請將其與全局線程池分開放置5個線程。 而且,這兩個請求被提交後,從全局池10個線程被佔用和1個任務仍處於等待(從第一個請求) – Amriteya

回答

1

解決此問題的一種方法可能是創建可調用方法來處理元素列表而不是單個元素。例如,如果要刪除請求中的x項目,則可以創建x/5元素列表,並將此列表傳遞給可調用函數。這樣,通過代碼,您可以確保每個請求最多隻能使用5個線程。你必須小心處理異常情況。 (例如,您可以返回elementID的Map來產生枚舉,其中的結果可能是成功的,可重試的excepiton或不可重試的異常。)

此方法可能因您嘗試實現的目標而異。

+0

這是兩種不同的解釋,我從你的回答理解: 所以,如果我得到20個任務在第一個請求中,我將它分成4個項目的列表。 [1-5,6-10,11-15,16-20]並提交1-5作爲一個工作(線程)。其他15人會發生什麼? 或者我將4組任務提交到4個線程?首先,如果我有超過5 * 5個任務(比如30),我該如何處理?其次,在我的用例中,我希望每個線程都有一個任務。所以當我向一個線程提交一個組時,我必須再次進行並行化,這會導致不必要的開銷,並且會違反我的第一個條件,即一個請求一次只能有5個線程。 – Amriteya

+1

如果您有20個請求,您將創建5個每個4個元素的列表,並在該方法中連續處理這4個元素。如果您有50個請求,您將創建5個每個10個元素的列表並連續處理10個元素。你在這裏做的是確保你將任務分解成可以分解成5個可以並行運行的小任務。 –

+0

該方法聽起來不錯。我看到的唯一問題是阻止一個線程編排列表迭代。這將是一項沉重的任務,因爲它會提交4個工作等待他們完成,然後再提交4個工作等等。 如果我可以使用ThreadPoolTask​​Executor,我可以提交隊列中的所有作業並檢索該線程。我正在尋找解決方案,我可以在隊列中提交工作。 – Amriteya

0

我會這樣做的方式是創建一個能夠節制任務的類。每個請求都會創建一個油門並將其所有任務提交給油門;油門會將前5個(說)任務提交給Executor並將其他人放在列表中。由於提交的任務已完成,可以提交其他任務。

要確定何時完成任務,節流閥可以定期輪詢提交的任務,檢查期貨的isDone()方法以查看它們是否完成,或者它可以阻止一個Future的get()方法,直到它爲止完成並檢查另一個未決的期貨,或者如果你想變得複雜一點,請求線程可以等待()節流閥,任務可以設置爲在完成時通知()節流閥,這樣請求線程會然後醒來並檢查完成的任務。