2013-02-27 111 views
0

賬單類具有與國家明智賬單相關的所有邏輯。它從數據庫中獲取結果,然後爲用戶開票。帳單類實現Runnable。我想根據國家參數並行執行結算,以便大量用戶(500萬+)非常快速地結算。現在需要數小時完成。ThreadPoolExecutor正在運行的應用程序

我想實現ThreadPoolExecutor執行Billing類,但很困惑如何?以下有什麼區別或者我做錯了什麼?請建議!區共有20個國家,但我在這裏粘貼僅5

//for 20 countries ThreadPoolExecutor (20,20,20.......)???? 

ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 5, 5, TimeUnit.SECONDS, 
new ArrayBlockingQueue<Runnable>(10), new ThreadPoolExecutor.CallerRunsPolicy()); 

executor.execute(new Billing("UK")); 
executor.execute(new Billing("USA")); 
executor.execute(new Billing("Germany")); 
executor.execute(new Billing("Spain")); 
executor.execute(new Billing("Italy")); 

OR

ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 5, 5, TimeUnit.SECONDS, 
new ArrayBlockingQueue<Runnable>(10), new ThreadPoolExecutor.CallerRunsPolicy()); 
for(int i=0;i<5;i++) // for 20 countries i<20?? 
{  

    executor.execute(new Billing("UK")); 
    executor.execute(new Billing("USA")); 
    executor.execute(new Billing("Germany")); 
    executor.execute(new Billing("Spain")); 
    executor.execute(new Billing("Italy")); 
} 

while (! executor.isTerminated()) { 
    try{ 
     executor.awaitTermination(100, TimeUnit.SECONDS); 
    }catch(InterruptedException iE) 
    { 
     iE.printStackTrace(); 
     System.out.println("Executor Exception: "+ iE); 
    } 

在此先感謝!

+1

你只是詢問是否要使用'for'循環?你的意思並不完全清楚。 – 2013-02-27 16:17:47

+0

@TimBender ...........我修改了我的問題... – 2013-02-27 16:25:58

+0

@TimBender ..我很困惑在實施ThreadPoolExecutor執行Billing類..我該如何實現?我是否必須在ThreadPoolExecutor中使用For循環?或者它將並行運行所有計費類.. – 2013-02-27 16:28:23

回答

1

循環解決方案看起來不正確。不需要多次執行相同的Runnable

你既corePoolSizemaximumPoolSize設置爲5,這意味着執行程序將保持線程的數量在游泳池5,即使它們是空閒實例ThreadPoolExecutor。它還說池中的線程數不能超過5

在此位置,您可以預計至多5線程正在並行執行任務(Billing對象)。

隨着您繼續提交Billing對象到executorexecute方法它們被添加到您提供的ArrayBlockingQueue。此隊列的大小爲10。在某些情況下,隊列中的隊列可能已經處於最大容量並且不能承擔更多任務,在這種情況下,任務將被拒絕並提供給ThreadPoolExecutor構造函數中提供的RejectedExecutionHandler。它的工作是用已實施的方法rejectedExecution處理被拒絕的任務。

如果你想找到是否有任何被拒絕的任務,你必須提供自己的RejectedExecutionHandler而不是使用默認的ThreadPoolExecutor.CallerRunsPolicy。你可以像這樣做:

ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 5, 5, 
     TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(10), 
     new RejectedExecutionHandler() { 
      @Override 
      public void rejectedExecution(Runnable r, 
        ThreadPoolExecutor executor) { 
       System.out.println("I got rejected: " + r); 
       if (!executor.isShutdown()) { 
        r.run(); 
       } 
      } 
     }); 
+0

@NishantShresthth ..當我嘗試執行(NewBilling(「國家」))一些帳單類並沒有執行..例如20只有16只正在運行... – 2013-02-27 16:30:30

+0

或者我誤認爲聲明ThreadPoolExecutor只有ArrayBlockingQueue (10)...我應該把它變成20? – 2013-02-27 16:33:59

+0

如果您的「結算」任務非常耗時,如果隊列在某些情況下已滿,則某些任務可能會被拒絕。在這種情況下,增加隊列的大小應該會有所幫助。 – 2013-02-27 17:09:21

0

我不確定你瞭解循環如何工作。不同之處在於第二個代碼塊將在每個列出的國家/地區運行計費5次。

+0

但不使用for循環.. Threadpoolexecutor沒有執行所有20 Billings? – 2013-02-27 16:32:03

0

假設你正在談論的代碼for環部分並不明顯,將如何工作。

理想的循環將是這個樣子:

for(String country : countryCollection) { 
    executor.execute(new Billing(country)); 
} 
0

你有沒有考慮使用enum

static class Billing implements Runnable { 

    enum Country { 
    UK, 
    USA, 
    Germany, 
    Spain, 
    Italy; 
    } 

    public Billing(Country country) { 
    } 

    @Override 
    public void run() { 
    } 
} 
public void test() { 
    ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 5, 5, TimeUnit.SECONDS, 
     new ArrayBlockingQueue<Runnable>(10), 
      new ThreadPoolExecutor.CallerRunsPolicy()); 
    for (Billing.Country country : Billing.Country.values()) { 
    executor.execute(new Billing(country)); 
    } 
} 
1

第一:忘記循環

for(int i=0;i<5;i++) // for 20 countries i<20?? 
{  

    executor.execute(new Billing("UK")); 
    executor.execute(new Billing("USA")); 
    executor.execute(new Billing("Germany")); 
    executor.execute(new Billing("Spain")); 
    executor.execute(new Billing("Italy")); 
} 

這一切賬單多次遍歷。

做的正確的事情是在第一個片段:

executor.execute(new Billing("UK")); 
executor.execute(new Billing("USA")); 
executor.execute(new Billing("Germany")); 
executor.execute(new Billing("Spain")); 
executor.execute(new Billing("Italy")); 

另一個錯誤在於對終端的檢查:

while (! executor.isTerminated()) { 
    try{ 
     executor.awaitTermination(100, TimeUnit.SECONDS); 
    }catch(InterruptedException iE) 
    { 
     iE.printStackTrace(); 
     System.out.println("Executor Exception: "+ iE); 
    } 
} 

Executor.awaitTermination的Javadoc說:

塊直到所有任務在關閉請求後完成執行,

但您永遠不會發出關閉請求。

在你的情況,你可以充分利用ExecutorCompletionService爲:

CompletionService<String> ecs = new ExecutorCompletionService<String>(executor); 
List<String> countries= Arrays.asList("UK","USA","Germany","Spain","Italy"); 
for(String country : countries) { 
    ecs.submit(new Billing(country),country); 
} 
// wait for completion 
for(int i=0;i<countries.size();i++){ 
     ecs.take(); // wait for next country completion 
} 
// all work completed, shutdown 
executor.shutdownNow(); 
+0

+1,但你永遠不會發出關機請求。 – 2013-02-27 17:13:38

0

另一種方式來思考實現這個就是看看The Fork/Join Framework。這看起來似乎可以真正從鍊鋼獲益。例如,你可以看起來相當乾淨地分解它。這基本上可以讓您打破用戶或部分用戶的計費任務,而不是讓一個看起來代表一個國家的線程在整個計費過程中工作。

你可以找到的鏈接庫:here if you are using a version of Java < 7

+0

我在Java 6上運行.. fork/join在java 7上? – 2013-02-27 20:26:07

+0

圖書館已經有一段時間了,我編輯了我的回覆以提供鏈接 – 2013-02-27 20:27:20

相關問題