Newsgroup: it.comp.java
Titolo: Fermare un thread

Supponiamo che un thread sia basato su un loop con operazioni di I/O, e
quindi possa rimanere bloccato in attesa di dati. Qual'e' un buon modo
di implementare un comando per terminarne l'esecuzione, visto che non si
puo' usare un flag per farlo uscire "naturalmente" dal loop? Forse il
metodo interrupt()?

              
Network Distributed Applications @ CRS4
Center for Advanced Studies,Research and Development in Sardinia
http://www.crs4.it/~dcarboni/whoami/
     Tel.: ++39 070 2796 303
----------------------------------------------------------------

metodo interrupt()?
In teoria si', in pratica non sempre; su NT per un noto bug di console, ad 
esempio, se un un thread e' bloccato in read(), interrupt non fa nulla (ancora 
in JDK1.3). Ad es, in
public class T {
 public static void main(String args[]) throws Exception {
  Thread t = new Thread(new Runnable() {
  	public void run() {
  		try {
	  		System.in.read();
	  		System.out.println("Thread secondario interrotto");
  		} catch(IOException e) {
  			e.printStackTrace();
  		}
  	}
  });
  t.start();
  Thread.currentThread().sleep(500);
  t.interrupt();
  System.out.println("Thread main terminato");
 }
}
il thread t su Solaris solleva una InterruptedIOException, su NT resta 
bloccato. In generale l'I/O interrompibile e' uno dei problemi piu' spinosi di 
compatibilita', e su win32 un casino vero e proprio.
Con le sockets, un workaround comune e' di usare timeouts, da JDK1.1 in su.
Per la console, un workaround che uso quando e' possibile e' di marcare il 
thread bloccante come daemon. Questo di per se' non risolve del tutto (perche' 
il thread bloccante esce *comunque* al termine dell'ultimo thread nondaemon, ma 
con un'architettura a thread di controllo (nondaemon), di input (bloccante, 
daemon) e "resto del mondo" (thread main, di solito) e un flag di controllo si 
puo' fare.
Purtroppo, pare che anche nel JDK1.3 la cosa non sia ancora risolta.
-- 
God is Real, unless declared Integer.
ObjectZone - 
http://space.tin.it/computer/csadun/

:
Un'aggiunta: incuriosito, ho dato un'occhiata, e pare che l'IO interrompibile 
sia stato deprecato l'anno scorso. La morale e', usare un textbox. ;-)


 Con le sockets, un workaround comune e' di usare timeouts, da JDK1.1
in su.
OK. Vedo che nella classe Socket c'e' un metodo per impostare un
timeout, in modo che sia lanciata un eccezione quando un'operazione di
lettura supera un certo tempo.
Pero' io voglio leggere da un InputStream fornito da un oggetto URL (in
pratica, il programma legge l'output di un CGI, e se il server e' lento
e l'utente si rompe le balle voglio che possa fermare la lettura
premendo "Stop" - come lo Stop dei browser).
Non capisco se c'e' un modo per ottenere lo stesso risultato a partire
dalla classe URL.
Per la cronaca, il metodo run() del thread che legge i dati e' piu' o
meno questo:
public void run() {
 ...
 boolean stopReading=false;
 URL u=new URL(s);
 URLConnection uc=u.openConnection();
 InputStream is = uc.getInputStream();
 BufferedReader rd = new BufferedReader(new InputStreamReader(is));
 String l;
 while((l = rd.readLine()) != null && !stopReading) {
  ...
 }
 stopReading=false;
}
Per fermare la lettura in condizioni normali, setto il flag stopReading
nel thread di controllo e il ciclo termina. Ma se si blocca
nell'esecuzione del readLine(), come fo? Ho provato con il metodo
interrupt(), che e' l'unico non deprecato per terminare i thread, e pare
funzionare, ma non sono convinto che sia un buon sistema (cioe' che non
abbia effetti collaterali imprevisti..)

 metodo interrupt()?
ciao
 vediamo se ho capito:
 potresti usare il metodo available() per scaricare i dati dallo stream, in
questo
 modo il flusso del programma non rimane bloccato:
while (true) {
..............
  while( mioInputStream.available() >0 ) {
   mioInputStream.read();
 }
............
}
Praticamente si tratta di scaricare dati da uno streaqm "pollando" lo stream
stesso.
Altrimenti devi mettere la lettura , questa volta bloccante, in un thread
separato (thread B)
e far comunicare questo thread con il thread che lo controlla (tread A),
tramite un semaforo
o un flag. Se dopo un certo tempo il semaforo e' ancora basso, il thread A
ammazza il thread B.
ciao
 Enrico

abbia effetti collaterali imprevisti..)
Non ne ha - pero' non funziona su tutte le JVM, per quel che ne so.


 ammazza il thread B.
Infatti questa e' la soluzione - circa, nel senso che non e'
indispensabile che la terminazione del thread di lettura sia automatica,
ma mi basta che ci pensi l'utente. Quindi se questo preme il tasto
"Stop", il thread della GUI ammazza quello di lettura. Pare che funzioni
:-)
BTW, qual'e' il modo "giusto" per ammazzare un thread, considerato che
con Java 2 sono stati deprecati i metodi come stop()?
Io ho usato:
 th.interrupt();
 th=null;
E' giusto? th=null lo faccio per dare th in pasto al garbage collector.
Infine: ho controllato sul developers forum di Sun. Il mio problema
iniziale, esattamente in quei termini, e anche il problema della
terminazione automatica di una lettura bloccata, sono gia' stati posti
senza altre soluzioni che non siano quelle della uccisione del thread.
In particolare, un programmatore si lamentava del fatto che leggendo a
partire da una URLConnection non fosse possibile specificare un timeout
per il blocco, e considerava il metodo del thread di controllo "una di
quelle cose alla C/C++ che Java dovrebbe risparmiarci". Ha risolto il
problema modificando i sorgenti della classe URLConnection del package
Net inserendo un timeout quando viene creato il socket per la
connessione.
Ai mali estremi, estremi rimedi... :-)

 Non ne ha - pero' non funziona su tutte le JVM, per quel che ne so.
Che stress :-/

 ha scritto nel messaggio
news:8oidm2$h5u$1...@serv1.iunet.it...


 Ai mali estremi, estremi rimedi... :-)
ciao
 si, i thread si ammazzano come hai fatto tu, cioe' ponendo il loro
riferimento
 a null. Come ti dicevo hai due modi:
1. Dedichi un thread a fare le letture dagli stream Internet. In questo
caso,
    se il frame non e' incompleto, il metodo read( ) e' bloccato
2. Se usi il metodo available( ) e non usi il thread
Personalmente preferisco il metodo available( ) perche' nei miei lavori
ho gia' fin troppi thread da gestire, per cui solo l'idea di doverne gestire
un altro mi viene mal di testa. Se usi available( ), lo puoi inserire
in un blocco del tipo :
     if ( utenteStufo = = false) {
         while( mioInputStream.available() >0 ) {
           mioInputStream.read();
        }
     }
utenteStufo e' una var. booleana gestita da un Listener che ascolta la
pressione
del tasto. Ricordati di chiudere lo stream.
Cosi' facendo, lavori in polling, cioe' scarichi i dati dallo stream quando
l'utente
non si e' stufato e quando il Program Counter passa per quel blocco.
Ho visto adesso che la classe BufferedReader non ha il metodo available( ),
la usi
perche' c'e' il metodo readLine( )?
Per cui ti conviene usare un bel thread.
spero di essere di aiuto
ciao
Enrico