PDA

View Full Version : [java] uccidere un thread


gaglioppo
16-05-2006, 08:52
ciao a tutti,

volevo sapere una cosa, visto che nn riesco a venire a capo di un problema con l'applicazione che sto realizzando.
Ho una classe che estende Thread che contiene il metodo run in cui il thread va a dormire.
Inoltre ho un bottone con associato un listener per far terminare il thread, ma cosi' com'è nn funziona. Come devo fare?


public class Listato extends Thread {

Thread corrente;

public Listato(){
corrente=currentThread();
}
void run(){

....
....
wait(4000);
....
....
}

public void Funzione(){

.....
.....
JButton stoppa=new JButton();
stoppa.addActionListener(new ActionListener() {
public synchronized void actionPerformed(ActionEvent evt) {
corrente.interrupt();
}
});
.....
....

}


grazie

andbin
16-05-2006, 09:24
ciao a tutti,

volevo sapere una cosa, visto che nn riesco a venire a capo di un problema con l'applicazione che sto realizzando.
Ho una classe che estende Thread che contiene il metodo run in cui il thread va a dormire.
Inoltre ho un bottone con associato un listener per far terminare il thread, ma cosi' com'è nn funziona. Come devo fare?In che senso non funziona??? Dovrebbe funzionare. L'unica cosa a cui devi stare attento è che se interrompi il thread mentre è su una wait(), il thread riceve una eccezione InterruptedException che devi catturare ad esempio con:
...
try {
wait(4000);
} catch (InterruptedException e) {
...
}
...

gaglioppo
16-05-2006, 09:39
l'eccezione l'ho catturata, avevo tralasciato di scriverla,
fatto sta che il thread nn si ferma :-(

Non di dovrebbe arrestare l'esecuzione di run()?
invece continua come se nulla fosse...

non è che nel listener non riesce a funzionare interrupt()?

PGI-Bis
16-05-2006, 09:43
L'unico modo per uccidere un Thread Java (in condizioni di normalità) è per esaurimento: quando non ha più nulla da fare ci lascia le penne.

interrupt() ha due effetti, che dipendono dallo stato del Thread che riceva l'invocazione.

Nel caso di Thread in attesa (vuoi, per un wait, uno sleep o un join) è generata un'eccezione InterruptedException.

Altrimenti muta solo il valore di uno stato.

La javadoc è naturalmente più esaustiva sull'argomento.

In entrambi i casi, il concreto esaurimento del Thread dipende dalla gestione esplicita della condizione terminante. Nel caso di suscettibilità al rilascio dell'eccezione InterruptedException è ciò che scrivi nel blocco di gestione (il catch) a stabilire se il Thread terminerà o meno. Nel caso di indifferenza alla stessa eccezione, occorre che, tra ciò che il Thread esegue come compito, vi sia il controllo periodico dello stato di interruzione.

Esempio: interrupt.

private Thread runner; //esegue run
private boolean doTask = true;

public void start() {...}

public void stop() {
if(runner != null) runner.interrupt();
}

public void run() {
while(eseguiCompito()) {
//fai qualcosa
try {
Thread.sleep(500);
} catch(InterruptedException ex) {
cancellaEsecuzione();
}
}
}

private synchronized void eseguiCompito() {
return doTask;
}

private synchronized void cancellaEsecuzione() {
doTask = false;
}

stop() invoca interrupt. Quando il Thread si troverà in pausa, verificherà lo stato "interrupted" e, nel caso in cui sia vero (cioè se qualcuno abbia chiesto al Thread di interrompere il suo compito) anzichè entrare in pausa sputerà un'eccezione InterruptedException. A quel punto la palla passerà al blocco catch, che semplicemente falsifica la condizione di ripetizione del ciclo while. Il Thread continuerà la sua esecuzione, il while cederà il passo e il compito del Thread si esaurirà.

In questo caso "interrupt" è superfluo: sarebbe stato sufficiente controllare direttamente la condizione del ciclo while. In altri casi (in particolare quando il Thread consumi dei dati per ricavare i quali è costretto ad una attesa) si usa accanto al controllo di una condizione non dissimile da quella proposta.

gaglioppo
16-05-2006, 10:02
Grazie per i suggerimenti,
mi sa che l'interrupt nn fa al caso mio, uso notifyAll.
Non sono sicuro se nel syncronized ci vada corrente e se ci possono
essere problemi nel fare return su run().

Ho trovato questa soluzione, per ora:

public class Listato extends Thread {

Thread corrente;

public Listato(){
corrente=currentThread();
}
void run(){

....
while(!interruzione || altrecose){
wait(4000);
}
if(interruzione)
return;
....
....
}

public void Funzione(){

.....
.....
JButton stoppa=new JButton();
stoppa.addActionListener(new ActionListener() {
public synchronized void actionPerformed(ActionEvent evt) {
synchronized(corrente){
interruzione=true;
corrente.notifyAll();
}
}
});
.....
....

}

PGI-Bis
16-05-2006, 10:30
Be', il codice qualcosina di strano ce l'ha tuttavia parlo senza cognizione del tuo sistema di riferimento.

In linea generale, crei un'estensione di Thread quando usi un approccio actor-oriented alla concorrenza e usi Runnable quando ti affidi ad una politica task-oriented.

Nel tuo caso esprimi un mix.

Il tuo Thread "corrente" è anomalo ma questo non vuol dire che sia sbagliato: ripeto, dipende da quello che hai mente di fare.

andbin
16-05-2006, 11:00
In linea generale, crei un'estensione di Thread quando usi un approccio actor-oriented alla concorrenza e usi Runnable quando ti affidi ad una politica task-oriented.Mi spieghi meglio questo??

Il mio libro (quello per SCJP) spiega che estendere da Thread non è una buona pratica dal punto di vista della OOP. Questo perché "estendere" una classe significa "specializzarla", darle un comportamento più specifico. Nel caso di Thread, lo si dovrebbe estendere per creare una versione più specializzata di Thread. Ma quello che si fa in genere è semplicemente fargli eseguire un lavoro, non specializzarlo.
Quindi si dovrebbe ricorrere alla implementazione di Runnable, che tra l'altro permette così di estendere da un'altra classe (es. Applet).
Dico bene??

PGI-Bis
16-05-2006, 12:56
Sarò spudorato (e accetto ovviamente critiche in tal senso) ma quel libro ha un'idea almeno grossolana dell'orientamento agli oggetti.

Dire che il rapporto tra due definizioni di oggetti delle quali una è estensione dell'altra sia di genere a specie non è sempre corretto. Prendi il caso ideale di questi due personaggi:

public class Ping {
public void stampaTesto() {
System.out.println("ping");
}
}

public class Pong extends Ping {
public void stampaTesto() {
System.out.println("pong");
}
}

Pong è una specie di Ping? Se concordiamo, come mi sembra generalmente accettato, che nei termini dell'orientamento agli oggetti la definizione di un comportamento è sempre irrilevante (conta la dichiazione del possesso di una capacità, non come la capacità si svolta) allora diremmo che Pong è una specie di Ping sulla base di un elemento, la diversa definizione di stampaTesto, che abbiamo convenuto essere sempre trascurabile.

Negando la premessa, vale a dire assumendo che anche la definizione sia rilevante, salveremmo il rapporto di genere a specie tra Ping e Pong: Pong è specie di Ping perchè, pur dichiarando gli stessi comportamenti, ha una definizione specializzante e la definizione conta.

Il problema è che se la definizione conta, allora la definizione deve essere pubblicata: in quanto elemento specializzante, l'oggetto che la possiede deve renderla nota ai terzi che altrimenti questi non potrebbero distinguere tra lui ed il suo genere. Cosa quantomeno bizzarra perchè che per via del principio di identità due oggetti che non possiedano caratteristiche distinguenti sono lo stesso oggetto.

Salviamo capra e cavoli? Per me si può. Il primo passo è prescindere dal linguaggio. Io ritengo che la programmazione orientata agli oggetti non preesista ai linguaggi di programmazione orientati agli oggetti ma sono certo che preesistente è la prospettiva orientata agli oggetti.

La prospettiva orientata agli oggetti ci dice che il rapporto di genere a specie è solo una delle possibili relazioni tra almeno due oggetti in un ambiente.

Esiste almeno un caso esemplare in cui la definizione di un comportamento, nell'identità delle dichiarazioni, è elemento che distingue due oggetti, cioè partecipa all'identità di uno ma non dell'altro: è il caso del rapporto tra un prototipo ed il suo derivato. Prototipo e derivato non sono in rapporto di genere a specie: sono semmai esemplari diversi di uno stesso tipo concettuale.

Con un certo imbarazzo terminologico io definisco prototipo un oggetto pienamente formato e abile che è preso come punto di riferimento di un secondo oggetto, uguale al prototipo salvo per una diversa definizione di alcuni comportamenti.

Abbiamo due oggetti, abbiamo una relazione tra questi due oggetti, relazione qualitativamente diversa dal rapporto di genere a specie.

Con questo due di bastoni in mano, se torniamo al linguaggio Java, riusciamo a preservare il carattere distinguente della diversa definizione senza richiedere che la definizione sia pubblicata. Se ho due classi delle quali una è derivata dell'altro ed entrambe le classi possiedono le stesse dichiarazioni di capacità so che l'una differisce dall'altra come il prototipo differisce dal suo derivato. Prototipo e derivato e derivati diversi dello stesso prototipo, pur in costanza di dichiarazione (hanno tutti gli stessi metodi, in Javese) preservano la loro identità in forza della clausola di derivazione.

Giusto per non lasciare dei fili penzolanti, ricordo che il rapporto di genere a specie in Java si esprime attraverso la dichiarazione di due interfacce delle quali una sia estensione dell'altra (X ha tutte le capacità di Y più alcune specializzanti). Il rapporto che sussiste tra un interfaccia e una classe è di tipo a esemplare (X è una donna perchè possiede tutte le caratteristiche della categoria donna: magari ne possiede altre ma è indifferente al fine della verità "x è una donna").

Tornando a noi, un attore concorrente è un pezzo del sistema che esegue il proprio lavoro parallelamente agli altri attori. Un compito concorrente è un insieme di operazioni destinate ad essere affidate ad un Thread per l'esecuzione concorrente. Runnable è il prototipo dei compiti concorrenti e Thread è il prototipo degli attori concorrenti.

E qui tiro il fiato perchè se no mi viene un coccolone alle dita :D

PGI-Bis
16-05-2006, 12:59
A scanso d'equivoci: all'esame scrivi quello che c'è sul libro (Gosling, Arnold, Holmes?) perchè è quello che conta per quell'esame.

andbin
16-05-2006, 13:20
Sarò spudorato (e accetto ovviamente critiche in tal senso) ma quel libro ha un'idea almeno grossolana dell'orientamento agli oggetti. [...] :O Questo tuo post lo devo sicuramente rileggere bene un paio di volte per poterlo capire appieno!

dupa
16-05-2006, 13:20
Mi spieghi meglio questo??
Quindi si dovrebbe ricorrere alla implementazione di Runnable, che tra l'altro permette così di estendere da un'altra classe (es. Applet).
Dico bene??

quando estendi hai che la nuova classe è quella vecchia.

Un cerchio è una forma.
Un quadrato è una forma.

Quindi cerchio o quadrato, estendono forma.

Se estendi una applet allora la tua classe è una applet, come può a livello logico essere anche un Thread?
Al massimo la applet avrà dei thread.
No?

andbin
16-05-2006, 13:25
sul libro (Gosling, Arnold, Holmes?)Il "The Java Programming Language, 4th Edition" di Gosling dovrebbe giusto arrivarmi a casa tra pochi giorni... :fagiano:
Un bel tomo di 928 pagine da leggere e studiare ... :sbav:

PGI-Bis
16-05-2006, 13:30
E' un bel libro ma quando a un certo punto, trattando dei generici, Ahè scrive "questo è troppo complicato da spiegare qui, rimandiamo alla bibliografia" ti fa un po' girare le nocciole :D.

andbin
16-05-2006, 13:32
quando estendi hai che la nuova classe è quella vecchia.

Un cerchio è una forma.
Un quadrato è una forma.

Quindi cerchio o quadrato, estendono forma.Sì, lo so!!! Un gatto è-un animale, una Ferrari è-una automobile. ;)

Se estendi una applet allora la tua classe è una applet, come può a livello logico essere anche un Thread?
Al massimo la applet avrà dei thread.
No?Appunto. E io cosa ho detto di sbagliato??? (ho solo riportato cosa spiegava il mio libro). Comunque è per quello che si implementa Runnable.

andbin
16-05-2006, 13:36
E' un bel libro ma quando a un certo punto, trattando dei generici, Ahè scrive "questo è troppo complicato da spiegare qui, rimandiamo alla bibliografia" ti fa un po' girare le nocciole :D. :confused: Ma c'è tutto il capitolo 11 di 31 pagine dedicato ai Generic Types.

dupa
16-05-2006, 13:40
Bè anche se ferrari la vedo meglio come oggetto di c
Appunto. E io cosa ho detto di sbagliato??? (ho solo riportato cosa spiegava il mio libro). Comunque è per quello che si implementa Runnable.

Io sinceramente ho detto il contrario.
Personalmente io preferisco estendere Thread, cmq se qualcuno mi dà un esempio dove estendere thread non sarebbe corretto, sarei felice :)

PGI-Bis
16-05-2006, 13:44
Si, siamo tutti d'accordo sul fatto che un gatto sia un animale, che la panda sia un'automobile e che la pera sia un frutto. Il problema è perchè il gatto è un animale, perchè la panda è un'automobile è perchè la pera è un frutto. E se esistano relazioni diverse, come possano essere espresse, che utilità abbiano. E come i diversi linguaggi di programmazione consentano di rappresentare questi oggetti e queste relazioni.

PGI-Bis
16-05-2006, 13:45
:confused: Ma c'è tutto il capitolo 11 di 31 pagine dedicato ai Generic Types.

Appunto, è per quello che girano! Tanto valeva non scriverlo e morta lì :muro:

andbin
16-05-2006, 14:20
Si, siamo tutti d'accordo sul fatto che un gatto sia un animale, che la panda sia un'automobile e che la pera sia un frutto. Il problema è perchè il gatto è un animale, perchè la panda è un'automobile è perchè la pera è un frutto. E se esistano relazioni diverse, come possano essere espresse, che utilità abbiano. E come i diversi linguaggi di programmazione consentano di rappresentare questi oggetti e queste relazioni.Guarda, ne sai sicuramente più tu di me su Java. Comunque il mio libro spiega bene 2 concetti: IS-A e HAS-A. L'ereditarietà e l'implementazione delle interfacce sono in pratica l'espressione del concetto IS-A. Il possedere e utilizzare all'interno di una classe A un riferimento alla classe B è l'esempio di HAS-A.

Appunto, è per quello che girano! Tanto valeva non scriverlo e morta lì :muro:Comunque si trovano molte info in giro sui Generics. Sul mio libro x SCJP sono dedicate 35 pagine. In più c'è il tutorial in pdf (http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf).

PGI-Bis
16-05-2006, 14:34
Si, ma prova a chiederti non come si esprima la relazione IS-A o HAS-A in Java ma perchè A è un B o A possiede un B. Quel libro ti dirà che A è un B perchè A implements B o che A è un B perchè possiede le caratteristiche essenziali di un B. La prima è una petizione di principio, la seconda è aria fritta perchè poi dovrebbe dire quali caratteri siano essenziali e quali no e il problema dell'approccio classico è proprio l'assenza di un metro dell'essenzialità.

Non dare per scontato che io ne sappia più di te su Java: lo spirito santo è un po' che non infonde più e quello che so di Java l'ho letto sugli stessi libri che hai letto tu e che leggono tutti.

C'è un problema più generale di approfondimento di quello che leggiamo e che, a mio giudizio, aiuterebbe a cambiare l'attuale metodologia di sviluppo del software che, per chi ne se fosse accorto, è fatta così: io scrivo una stronzata, tu la leggi, lui la applica, il software non funziona e tutti ci stupiamo :D.

PGI-Bis
16-05-2006, 14:36
Sui generici c'è una cosa che io trovo divertentissima. Se leggi questo o quel libro, poi passi a questo o quel riferimento bibliografico e così via, scopri che alla fine della fiera fatto tutti riferimento ad un lavoro di Higarashi (si scrive così?) e Viroli. Io l'ho letto e non ho capito una mazza :D. Spero che agli altri sia andata meglio :D.

gaglioppo
17-05-2006, 08:09
uhm.. la discussione sta volgendo sul pesante e a stento riesco a seguirvi

In ogni caso proverei a spiegare meglio il mio lavoro, in modo che si possa capire meglio quello che devo fare.

Ho n siti web da visitare e siccome ogni sito potrebbe richiedere delle attese per fornirmi i risultati, anche di ore, ho pensato, spero bene, che per ogni sito ci volesse un thread indipendente dagli altri.
Naturalmente se qualcosa va storto, se cade la connessione per esempio, oppure se l'utente decide cliccando su un bottone di fermare uno o più processi, i threads si devono interrompere in qualche modo.

All'università mi hanno fatto usare sempre il seguente approccio:

1 main che lancia n Operai
1 classe Operaio che estende thread e che esegue Gestore.Costruire()
1 classe Gestore che contiene il metodo Costruire() che poteva essere:
- syncronized (tutto o in parte) con wait e notifyAll
- sincronizzazione con monitor di Hoare
- sincronizzazione con semafori
(questi ultimi due sono state implementate dal mio prof., almeno cosi' ci so, dentro fanno riferimento a syncronized, con code, anche a priortià)

Spero di essere stato un pò piu' chiaro.