Newsgroup: it.comp.java
Titolo: thread e interrupt()

Ciao a tutti,
sto osservando un fatto piuttsto strano.
Ho una classe fatta così:
------ codice ---------
public class Crawler implements Runnable {
 
  public void run() {
 
    Thread.currentThread().setName(paginaIniziale.toString());
 
    //faccio alcune cose ...
    while(...) {
      if(devoTerminare())
        return;
 
      //faccio alcune cose ...
 
      while(...) {        
        if(devoTerminare())
          return;
 
        //faccio alcune cose ...
      }
      segnalaFine();
    }
 
 
    private boolean devoTerminare() {
        if(Thread.interrupted()) {
            segnalaFine();
            return true;
        }
        return false;
    }
 
 
    private synchronized void segnalaFine() {
        //avverto chi di dovere che questo thread ha
        //finito ...
    }
}
---------- fine codice --------
Ho omesso tutte le parti che non hanno a che fare con la classe thread.
In un altro punto dell'applicazione uso degli oggetti di questa classe per
creare dei thread che unisco in un ThreadGroup.
Se tutti terminano normalmente non ci sono problemi. Se l'utente clicca su
un pulsante "interrompi" viene chiamato interrupt() sul ThreadGroup e
quindi per quanto ne so su ogni thread. E qui arriva il bello. La maggior
parte termina come dovrebbe mentre qualcuno rimane attivo e
Thread.interrupted() restituisce sempre false. Come è possibile? Ho fatto
molte prove e sono certo che su tutti i thread viene chiamato interrupt(). 
E' possibile che se la chiamata di interrupt() avviene in qualche condizione
stramba (tipo thread bloccato in operazioni di rete o simili) il flag
interrupted non venga impostato?
Non riesco proprio a capire.
Grazie
Matteo
-- 
chi sono e soprattutto chi non sono:
http://www.ilnomedeldominio.it
un piccolo programma per studenti universitari:
http://inutility.ilnomedeldominio.it/imsv/

 Non riesco proprio a capire.
Se guardi nella documentazione di Thread.interrupt() questa frase dovrebbe
chiarire tutto
"If this thread is blocked in an invocation of the wait(), wait(long), or
wait(long, int) methods of the Object class, or of the join(), join(long),
join(long, int), sleep(long), or sleep(long, int), methods of this class,
then its interrupt status will be cleared and it will receive an
InterruptedException."
Solo in questo caso, dopo che hai invocato interrupt() sul thread, la
funzione interrupted() restituisce false.
A dirtela tutta, io personalmente ho sempre usato una variabile interna
(oltre a interrupt) per fermare un thread, in questo modo:
public class StoppableTask implements Runnable {
  private Thread taskThread=null;
  private volatile boolean mustStop=false;
  private volatile boolean running=false;
  public StoppableTask() {
    taskThread=new Thread(this);
    taskThread.start();
  }
  public boolean isRunning() {
    return running;
  }
  public void stop() {
    mustStop=true;
    taskThread.interrupt();
  }
  public void run() {
    running=true;
    internalRun();
    running=false;
    //tutti i lavori dovranno essere eseguiti da internalRun(), da cui
    //puoi liberamente chiamare "return" per terminare il thread,
    //garantendo comunque un corretto aggiornamento dello stato "running".
  }
  private void internalRun() {
    do {
      //qui fai tutti i lavori che ti servono (compresi i vai
      //wait,sleep, ecc....
    } while(!mustStop);
  }
}
Spero possa esserti utile ^_^
-- 
Fermiamo Scientology prima che sia troppo tardi!!!
http://xenu.com-it.net
 - 
http://xenu.freewinds.cx/
(per rispondere personalmente leva IlDitoDalCulo)

Stavo sfogliando le pagine di una "rivista specializzata" quando matish mi
ha interrotto con la ridicola scusa:
Credo d'aver capito e cmq non mi convince.
In un punto che non vi avevo scritto perché non pensavo fosse problematico
(va a finire sempre così ... ;) quei thread chiamano dispose() su un
ProgressMonitor. Mi ritrovavo stranamente un stacktrace ogni tanto... e ora
ho capito.
dispose() sul ProgressMonitor chiama dispose() di Window. e guardate cosa fa
questo metodo:
DisposeAction action = new DisposeAction();
        if (EventQueue.isDispatchThread()) {
            action.run();
        }
        else {
            try {
                EventQueue.invokeAndWait(action);
            }
            catch (InterruptedException e) {
                System.err.println("Disposal was interrupted:");
                e.printStackTrace();
            }
            catch (InvocationTargetException e) {
                System.err.println("Exception during disposal:");
                e.printStackTrace();
            }
        }
Se non si trova nel thread event dispatcher (come nel mio caso visto che
viene eseguito dai miei thread) chiama una bella invokeAndWait().
Evidentemente a qualcuno dei miei thread l'interruzione arrivava in questo
momento causando una InterruptedException di cui non posso sapere niente se
non guardando lo stderr. Cioé il mio thread non puo' sapere che è stato
interrotto...
Ora vi domando: secondo voi non è un errore? Non sarebbe meglio che quel
metodo avendo catturato un' InterruptedException chiamasse interrupt() sul
thread corrente? Possibile che il thread si perda un'interruzione così?
Mi sembra quasi un bug di Swing ;)
Ciao


 Credo d'aver capito e cmq non mi convince.
Non so se e' la causa del tuo problema, ma tieni presente che ThreadGroup 
e' notoriamente broken. La cosa piu' utile da fare con ThreadGroup e' non 
usarlo. :)

 usarlo. :)
ok ;)
ma tu che ne pensi di quella cosa dell'interrupt()? Non credi che il thread
interrotto dovrebbe sapere di esserlo stato? Non sarebbe meglio mettere un
bel interrupt() in quel catch?
