我的时区早安。
我正在使用线程池开发一个小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?我可以在主线程中使用任何类型的连接吗?
提前致谢。 最诚挚的问候
答案 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