Вы можете использовать Blocking Queues в качестве буферов. Они обрабатывают все, вплоть до получения потоков, ожидающих других потоков, когда очереди пусты.
Обычно у вас будет два класса, по одному для каждого потока. Итак, у вас будет что-то вроде этого.
class PageToRetriveQueue implements Runnable{
PageBuffer partner;
BlockingQeueue queue = new LinkedBlockingQueue<Page>();
public void run(){
while(true){
Page p = partner.queue.take();
for(Link l : p){
queue.offer(l);
}
}
}
}
class PageBuffer implements Runnable{
PageToRetriveQueue partner;
BlockingQeueue queue = new LinkedBlockingQueue<Link>();
public void run(){
while(true){
Link l = partner.queue.take();
Page p = downloadPage(l);
queue.offer(p);
}
}
}
Вам нужно будет реализовать функции Page, Link и DownloadPage. Когда вы начнете, вам нужно будет seed одна из очередей, чтобы начать, вероятно, очередь ссылок. Стилистически плохая форма прямого вызова partner.queue.take (), скорее, у вас есть функция, которая абстрагирует это. Я пытаюсь сделать код кратким и легким для понимания здесь.
Надеюсь, это поможет!