我正在构建一个从网站下载文件的网络爬虫。我有一个生产者(链接获取者)和一个消费者(下载者)。
两者可以概括如下:
//Fetcher implements Runnable
public void run(){
while(String link = getLinkFromDatabase != null){
String htmlContent = HTTPrequest.getHTMLtoString(link);
ArrayList<String> links = HTTPrequest.getUrlsFromString(htmlContent); //Custom Parser/Extractor
ArrayList<String> files = HTTPrequest.getFilesFromString(htmlContent);//Custom Parser/Extractor
String SqlQueryAddLinks = "INSERT IGNORE DUPLICATE INTO [...]"; //Insert query for Links with unique key : sha256 of the url.
String SqlQUeryAddFiles = "INSERT IGNORE DUPLICATE INTO [...]"; //Insert query for Files with unique key : sha256 of the url.
Queries.sqlExec(SqlQueryAddLinks);
int RowAffected = Queries.sqlExec(SqlQueryAddFiles);
Queries.archiveLink(link);
Monitor.append(RowAffected);
}
}
//Downloader implements Runnable
public void run(){
while(String link = getFileFromeDatabase != null){
//You don't care of steps here I just download the file
if(fileDownloaded){
Queries.archiveFile(link);
Monitor.take();
}
}
}
现在我尝试同步两个线程,以确保链接不会太旧。为此,我使用Monitor(如William Stallings撰写的《操作系统:内部和设计原则》中所述)
public class Monitor{
int N = 10;
int count;
Condition notfull, notempty;
public Monitor(){
count = 0;
}
public void append(int nbr) throws InterruptedException{
if(count >= N){
notfull.wait();
}
count+=nbr;
notempty.signal();
}
public void take() throws InterruptedException{
if(count == 0){
notempty.wait();
}
count--;
notfull.signal();
}
现在的问题是,我想通过一个监视器启动多对提取器和下载器同步。我需要创建一个新的监视器对象并将监视器添加到我的Downloader和Fetcher类中吗?或者有更好的方法吗?这本书不是在谈论倍数生产者/消费者,而是在C++中使用函数parbegin(producer, consumer);
(我认为它是C++)。
只需仔细观察,由于多种原因,此代码无法编译,并且保证了运行时失败。
a) 您尝试调用静态方法take/append,但它们不是静态的。
b) 您尝试有2个Condition对象,但没有可重入锁。
c) 在等待/通知之前,您甚至没有锁定/解锁条件后面的可重入锁定
d) 您使用Condition.wait()而不是.await().
e) 您正在使用Condition.signal()而不是.signalAll()