2012-03-21 22 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