2012-03-21 33 views
3

早安我的時區。在動態線程數調用ExecutorService.shutdown

我使用線程池來開發一個小的Http機器人,從鏈接中行進每個page.When鏈接我發現了一個新的鏈接我創建一個新的線程,將探索新的一頁。 僞代碼。

pool = Executors.newFixedThreadPool(40); 

pool.execute(new Exploit(tree.getRoot())); 

在這種情況下,漏洞利用是實現Runnable接口,並有機會獲得游泳池的內部類,所以每一個線程發現一個鏈接時,將使用池添加一個新的「線程」像這樣:

for(Link n : links){ 
    pool.execute(new Exploit(n)); 
} 

我看到了很多的例子使用的ExecutorService類,但它們都使用相同的代碼排序是這樣的:

ExecutorService executor = Executors.newFixedThreadPool(NTHREDS); 
for (int i = 0; i < 500; i++) { 
    Runnable worker = new MyRunnable(10000000L + i); 
    executor.execute(worker); 
} 
    // This will make the executor accept no new threads 
    // and finish all existing threads in the queue 
    executor.shutdown(); 

在上面的代碼中,線程數量是靜態的,所以w ^母雞代碼調用關閉所有線程已經被添加到pool.I不能按照這個代碼,因爲在我的情況我沒有線程添加的靜態數量。我停止狀態,更多的線程添加到池是,當我達到了一個搜索深level.So我的問題是,我如何調用executor.shutdown在主線程?有什麼類型的連接,我可以在主線程中使用?

在此先感謝。 最好的問候

+1

讓我明白:您的系統遞歸掃描頁面中的鏈接,併爲找到的每個鏈接創建一個掃描任務。這個任務被安排在一個執行器中,並且當沒有更多的任務被執行時你想關閉執行器。兩個問題:(1)任務如何知道何時停止?即如果我在n級,我知道我應該/還是不掃描級別n + 1?你如何避免鏈接循環? – maasg 2012-03-21 14:31:46

+0

我的停止條件與級別成就有關。 當新任務看到父級有一個特定級別時,讓我們說3,那麼這個新任務將有4個,如果停止條件標記爲3,那麼將立即停止,並且沒有更多的任務到池中。 – tt0686 2012-03-22 15:37:20

+0

你是否最終用迄今爲止的信息解決了這個問題? – maasg 2012-03-26 10:57:18

回答

0

在你顯示的代碼中,你的確實有有一個靜態的線程數。 newFixedThreadPool創建具有固定數量的線程的線程池。

當你調用pool.execute,你不創建一個新的線程。您創建一個新任務,該任務將由其中一個現有線程執行。這就是線程池的全部要點。

+0

比我的回答更好解釋! – 2012-03-21 10:41:51

+0

感謝您的快速回答,但我沒有正確解釋我的問題。我知道我有一個靜態的線程數,我沒有的是一個靜態的任務數量,每個任務可以添加更多的taks到池中,在其他例子中,他們告訴我的是任務的靜態數量。因此,對於任務的動態數字,我如何在主任務中調用關機? – tt0686 2012-03-21 10:53:29

+0

只需調用'shutdown()'。任何已經創建的任務都會被執行,無論它們有多少個,那麼線程將全部停止。 – 2012-03-21 10:56:34

0

newFixedThreadPool將只設置在同一時間執行的線程的數目。它沒有指定可以放入執行程序服務的線程數。因此,您可以在主線程中添加任意多個線程,啓動​​和shutdown() ExecutorService,當您考慮不再添加時

1

您需要跟蹤池中當前有多少任務。在每次調用execute()之前增加一個計數器。然後在每項任務結束時遞減計數器,確保即使出現異常時也要執行此操作。

然後查看將關閉執行(一個發佈第一個任務),應該等待在while循環的代碼,如果計數器爲0

遞減代碼應使用通知喚醒主線程起來。

class TaskCounter { 
    private final Object lock = new Object(); 
    private long count; 

    public void taskStart() { 
     synchronize (lock) { 
     count++; 
     } 
    } 

    public void taskEnd() { 
     synchronize (lock) { 
     count--; 
     if (count == 0) { 
      lock.notify(); 
     } 
     } 
    } 

    public void waitForAllTasksToComplete() throws InterruptedException { 
     synchronize (lock) { 
     while (count != 0) { 
      lock.wait(); 
     } 
     } 
    } 
} 
+0

感謝您的asnwer :)。 我使用索引(AtomicInteger)開發了一個非常類似的解決方案,池本身就是我使用的監視器鎖 – tt0686 2012-03-22 15:39:46

2

你可以看看Phaser。您仍然可以使用固定數量的線程,但每次找到鏈接時都可以註冊另一方並根據該鏈接提交可運行內容。

Phaser phaser = new Phaser(1); 
ExecutorService e = Executors.newFixedThreadPool(n); 

public void crawl(final String url){ 
    visit(url); 
    phaser.arriveAndAwaitAdvance(); 
    e.shutdown(); 
} 

private void visit(String url){ 
    phaser.register(); 
    e.submit(new Runnable(){ 
     public void run(){ 
      //visit link maybe another visit(url)    
      phaser.arrive(); 
     } 
    }); 
} 

在這一點上e.shutdown()將永遠不會發生,直到所有鏈接已被訪問。

+0

+1 Nice選項,使用Java7。 – maasg 2012-03-23 15:25:18