2014-09-12 40 views
1

這是更多的Java併發設計問題。我正在研究需要爲許多不同客戶端處理許多消息的應用程序。如果兩條消息具有不同的客戶端名稱,則可以並行處理它們。但是,如果它們具有相同的客戶端名稱,則需要按順序進行處理。使用Java線程池,如何根據消息特性並行處理一些消息和其他消息?

實現此目的的最佳方式是什麼?

我目前的實現非常簡單:我寫了一個名爲OrderedExecutorPool的包裝類。它有一個單線程執行程序的列表。在其提交的方法,它下面的找出將任務提交到執行:

int executorNum = Math.abs(clientName.hashCode()) % numExecutors; 
executorList.get(executorNum).submit(task); 

這保證了與同一客戶的所有消息去同一個執行者,同時還支持並行方式爲不同的客戶端處理的消息。

有幾個與此設計問題:

1)如果大多數客戶的名字有相同的散列碼,那麼只有少數執行者正在做的工作

2)如果一個客戶有很多消息,只有一個執行者可能無法跟上

有沒有一個優雅的解決方案可以解決上述缺點的問題?

編輯 clientName只是一個字符串。我只是調用它的String.hashCode()方法。

+0

你是否用合理的方法重載hashCode? 它確保您始終會爲唯一字符串返回唯一值嗎? 你確定你總是少於2^32個唯一的客戶端名稱(因此是hashcode)嗎? 你確定你現在的hashCode實現是否是無碰撞的? 如果你對任何這些問題回答「否」......你犯了一個錯誤,你的應用程序會崩潰/在某些時候產生錯誤的結果。 – specializt 2014-09-12 16:46:25

+0

「如果一個客戶端有很多消息,只有一個執行者可能無法跟上」,因爲您需要單個客戶端進行串行處理,唯一的選擇是少做一些工作,或者使其效率更高。 – 2014-09-12 16:48:46

+0

注意:Math.abs(Integer.MIN_VALUE)<0.您可以使用'&'代替。例如'(clientName.hashCode()&Integer.MIN_VALUE)%numExecutors;'或如果numExecutors是2的冪'clientName&(numExecutors - 1);' – 2014-09-12 16:51:20

回答

0

我不知道jdk內建解決方案。我已經使用這個基本邏輯在我目前的工作中實現了一個自定義執行器解決方案。

  • 保持CLIENTNAME的內部地圖的工作隊列(每個客戶都有自己的隊列)
  • 工作進來的客戶端時,將其添加到他們的隊列
    • ,如果這是在第一份工作隊列中,創建一個Runnable此客戶端名/隊列,並將其推入「真正的」執行者(標準的JDK的線程池)
  • Runnable接口IMPL只是消耗的任務從單一的客戶端隊列中,直到空,然後退出

這個簡單的實現是「貪婪」的方法(客戶端將繼續工作,直到其隊列爲空)。如果您的客戶端數量多於底層線程,則您可能需要更「公平」的方法,即客戶端執行一些任務並在底層執行程序中重新排隊(從而允許其他客戶端完成一些工作)。