在动态线程号中调用ExecutorService.shutdown

时间:2012-03-21 10:24:01

标签: java multithreading concurrency executorservice

我的时区早安。

我正在使用线程池开发一个小Http机器人,在每个页面中从链接到链接。当我找到一个新链接时,我创建一个新线程来探索新页面。 伪代码。

pool = Executors.newFixedThreadPool(40);

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

在这种情况下,Exploit是一个内部类,它实现了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();

在上面的代码中,线程的数量是静态的,所以当代码调用shutdown时,所有线程都已经添加到池中了。我不能遵循这段代码,因为在我的情况下我没有静态的线程数加上。我向池中添加更多线程的停止条件是当我达到深度搜索时。所以我的问题是,如何在主线程中调用executor.shutdown?我可以在主线程中使用任何类型的连接吗?

提前致谢。 最诚挚的问候

4 个答案:

答案 0 :(得分: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()将永远不会发生,直到访问过所有链接。

答案 1 :(得分:1)

您需要跟踪池中当前有多少任务。在每次执行execute()之前递增计数器。然后在每个任务结束时递减计数器,确保即使出现异常也要执行此操作。

然后,关闭执行程序的代码(发布第一个任务的代码)应该在while循环中等待,看看计数器是否为0。

递减代码应使用notify来唤醒主线程。

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();
         }
      }
   }
}

答案 2 :(得分:0)

在您显示的代码中, do 具有静态线程数。 newFixedThreadPool创建一个具有固定线程数的线程池。

当您致电pool.execute时,您不会创建新主题。您创建一个新任务,该任务将由其中一个现有线程执行。这是线程池的重点。

答案 3 :(得分:0)

newFixedThreadPool只会设置同时执行的线程数。它没有指定可以放在执行程序服务中的线程数。因此,您可以在主线程中添加任意数量的线程,当您考虑不再添加时,启动execute()shutdown() ExecutorService