Sto provando a scrivere un crawler Web con multithreading.Utilizzo Java ThreadPool
La mia classe di ingresso principale ha il seguente codice:
ExecutorService exec = Executors.newFixedThreadPool(numberOfCrawlers);
while(true){
URL url = frontier.get();
if(url == null)
return;
exec.execute(new URLCrawler(this, url));
}
L'URLCrawler recupera l'URL specificato, analizza il codice HTML estratti i link da esso, e gli orari collegamenti invisibili indietro alla frontiera.
Una frontiera è una coda di URL non distribuiti. Il problema è come scrivere il metodo get(). Se la coda è vuota, è necessario attendere la fine di qualsiasi URLCrawler e riprovare. Dovrebbe restituire null solo quando la coda è vuota e URLCrawler non è attivo.
La mia prima idea era di usare un oggetto AtomicInteger per contare il numero corrente di URLCrawlers funzionanti e un oggetto ausiliario per le chiamate notifyAll()/wait(). Ogni crawler all'avvio incrementa il numero di URLCrawlers funzionanti correnti e all'uscita li decrementa e notifica all'oggetto che è stato completato.
Ma ho letto che notify()/notifyAll() e wait() sono metodi un po 'deprecati per fare comunicazioni thread.
Che cosa dovrei usare in questo modello di lavoro? È simile ai produttori M e N consumatori, la questione è come affrontare l'esaurimento dei produttori.
Sì, questa è una soluzione per uno stato stazionario. Ma come affrontare allora la situazione quando nessuno degli URLCrawlers mette in coda gli URL? Con una coda bloccante la frontiera bloccherà all'infinito. –
In tal caso è possibile avere un metodo crawlerDone() sull'oggetto di frontiera che viene chiamato ogni volta che un UrlCrawler termina il lavoro. Questo metodo insieme all'approccio contatore che hai suggerito, puoi testare (nel tuo metodo di frontiera) se tutti i crawler hanno finito. Se ciò è vero, get() può restituire null senza bloccare la frontiera – naikus
può essere una coda di blocco della capacità fissa. un buon candidato per quella capacità è il numero di Crawlers –