I give my program over than 600 links, stocked in an ArrayList
to get the title of the webpage, using JSoup (among others). For every link (using a for loop), I create a new thread (using thread.start()
) and pass the link through my program, I wait for my thread to finish (with thread.join
) before launching a new thread (simultaneous execution would cause some problems, I did that to prevent an unexpected thread end to stop the execution for the other links).
The problem is that sometimes, JSoup throws a SocketTimeoutException (which I'm supposed to catch), which makes my program freeze. I don't know why the execution stops even surrounded with a try/catch
.
Here's a piece of my code, maybe that could help you understand :
// In the method actionPerformed() of my JPanel
for(final String link : links)
{
Thread t = new Thread()
{
public void run()
{
Analyzer.process(link);
}
};
t.start();
try
{
t.join();
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
And in my process :
// method process() of my Analyzer class
try
{
Document doc = Jsoup.connect(lien).userAgent("Mozilla").timeout(5*10000).get();
// ^ EXCEPTION THROWN HERE ! ^
title = doc.title();
}
catch (Exception e)
{
e.printStackTrace();
erreurs+="Erreur lors de la lecture du titre\n";
}
It's annoying because the process is veeery long, I let it run for the night, and find today that my program froze at the 54th link. ^^' Thank you in advance !
EDIT - UPDATE
SercanOzdemir suggested me to use ExecutorService, instead of creating threads and making start()-join(), so I tried :
ExecutorService ex = Executors.newSingleThreadExecutor();
for(final String link : links)
{
System.err.println("-- "+i+" --"); //DEBUG
ex.execute(new Runnable(){
@Override
public void run(){
try
{
Analyzer.process(link);
}
catch( Exception e )
{
e.printStackTrace();
}
}
});
i++; //DEBUG
}
ex.shutdown();
But it prints only my debug links. Any idea of why it doesn't run my process ?
I've not tried this with jsoup but it is a simple way of creating threads to do a task and monitoring their status.
ExecutorService executorService = Executors.newCachedThreadPool();
Future future = null;
for(final String link : links)
{
future = executorService.submit(new Runnable(){
@Override
public void run(){
try{
Analyzer.process(link);
}
catch( Exception e ){
e.printStackTrace();
}
}
});
while(future != null
&& !future.isDone()
&& !future.isCancelled())
{
try {
Thread.sleep(2000); // Or do something else
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
executorService.shutdown();
The code in your updated question won't work because you are creating the service and instantly overwriting it without waiting for it to complete.
ExecutorService ex = Executors.newSingleThreadExecutor();
for(final String link : links)
{
System.err.println("-- "+i+" --"); //DEBUG
ex.execute(new Runnable(){ //Here it is created
@Override
public void run(){
try
{
Analyzer.process(link);
}
catch( Exception e )
{
e.printStackTrace();
}
}
});
i++; //DEBUG
//a split second later this loop finishes and overwrites the service again
}
ex.shutdown();