我正在尝试编写一个多线程的网络爬虫。
我的主入口类具有以下代码:
ExecutorService exec = Executors.newFixedThreadPool(numberOfCrawlers);
while(true){
URL url = frontier.get();
if(url == null)
return;
exec.execute(new URLCrawler(this, url));
}
URLCrawler会获取指定的URL,解析HTML并从中提取链接,然后将未见过的链接排入前沿队列。前沿队列是一组未被爬取的URL。问题在于如何编写get()方法。如果队列为空,则应等待任何URLCrawlers完成后再尝试。只有在队列为空且没有当前活动的URLCrawler时,它才应返回null。
我的第一个想法是使用AtomicInteger来计算当前工作的URLCrawlers数量,并使用辅助对象进行notifyAll()/wait()调用。每个爬虫在启动时都会增加当前工作的URLCrawlers数量,在退出时会减少它,并通知已完成的对象。
但我读到notify()/notifyAll()和wait()是一些已过时的线程通信方法。
在这种工作模式下,我应该使用什么?这类似于M个生产者和N个消费者,问题是如何处理生产者的枯竭。