|
|||||||
|
|
|
![]() |
|
|
Strumenti |
|
|
#1 | |
|
Junior Member
Iscritto dal: Oct 2008
Messaggi: 29
|
[JAVA] Uscire da un ciclo While/For con la pressione di un bottone
Salve a tutti,
è da poco che programmo in linguaggio Java, uso l'IDE NetBean 6.8 ... Sto creando un programmino che mi calcoli i tempi di carica di un tipo di batteria e tramite un ciclo while effettuo un conto alla rovescia per quanto riguarda il timer. Uso un bottone START per avviare il ciclo; ma mi sono accorto che se voglio bloccare il timer o comunque chiudere il programma devo forzare la chiusura di tutto il programma stesso. All'interno del while ho provato anche a mettere un if che mi controllasse in caso di bottone STOP premuto il cambio di una variabile booleana. Ma nulla! mi sono accorto che neanche me lo fa premere, non è in ascolto. Quote:
Attendo vostre risposte, per favore e grazie !
__________________
Toshiba Satellite A300-1GC ,Intel C2D P8400 3Mb L2 1066FBS, 4Gb DDR2, HD320Gb SATA, ATI Mobility Radeon HD3650 |
|
|
|
|
|
|
#2 |
|
Senior Member
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
|
il metodo actionPerformed viene eseguito dall'Event Dispatching Thread di AWT/Swing.
Codesto thread in pratica si occupa di prevelevare gli eventi che trova nella coda degli eventi di sistema di AWT/Swing e di processarli. Se tu dentro quel metodo (actionPerformed) quindi lanci un ciclo o comunque esegui delle computazioni che richiedono un certo tempo per essere portate a termine, per tutto quel tempo costringi l'EDT a eseguire il tuo codice e a non essere libero di tornare a prelevare eventi nella coda di sistema. Il che implica che se l'utente, nel mentre, tenta di premere un bottone o comunque di interagire con l'interfaccia grafica, si ritrova "in mutande" con un 'interfaccia che sembra non cagarlo di striscio, il che è quantomeno frustrante (per l'utente s'intende, l'interfaccia se ne frega altamente di queste piccole questioni umane La soluzione? Ovviamente tenere meno impegnato possibile il buon EDT e lasciarlo libero di tornare alle sue faccende. Nel tuo caso osservo che nell'actionPerformed distingui due sorgenti diverse di eventi: - quella identificata dall'actionCommand "Avvia Timer"; - quell'altra identificata dall'actionCommand "Ferma Timer". Noto anche altri due elementi: un flag di controllo e un ciclo che viene fermato dal menzionato flag (oltre che da un'altra condizione legata all'esecuzione del ciclo stesso). Ebbene, potresti risolvere l'enpasse così: * il flag di controllo lo dichiari fuori dal metodo actionPerformed, allo "scope superiore"; * in actionPerformed gestisci l'evento scatenato da "Avvia Timer" 1) resettando il flag di controllo esterno del ciclo e 2) lanciando un altro thread che esegue le tue operazioni cicliche e che legge periodicamente il flag di controllo esterno * in actionPerformed gestisci l'evento scatenato da "Ferma Timer" settando il falg di controllo per terminare il ciclo di operazioni eseguite dal tuo thread esterno. Un modo di rappresentare le operazioni cicliche da eseguire nel thread esterno potrebbe essere quello di codificarle come implementazione di un Runnable. A questo punto però sorgono almeno altre due questioni: 1) la neccessità di gestire in modo corretto il flag esterno visto che di fatto diventa una risorsa condivisa da 2 thread (l'EDT ci scrive sopra, l'altro thread ci legge. Dato che il flag è una variabile di tipo boolean, non occorre dichiararla come volatile, le letture e scritture su di essa sono atomiche). 2) la neccessità di gestire il caso in cui si verificasse l'evento "Avvia Timer" una seconda volta, mentre è già in esecuzione il tuo thread esterno, perchè l'utente ha cliccato nuovamente sul relativo bottone. Qui si potrebbe decidere di disabilitare il bottone durante la gestione dell'evento "Avvia Timer", per poi riabilitarlo durante la gestione dell'evento "Ferma Timer". Un'altra opzione è data dall'ultilizzo di un'altro flag specifico. In pseudo-codice: Codice:
// flag condiviso tra i thread
boolean flag;
...
// metodo eseguito dall'EDT
actionPerformed(ActionEvent e) {
if (e.actionCommand equals "Avvia Timer") {
resetto flag;
disabilito bottone "Avvia timer";
creo nuovo thread con istanza di MyTask;
lancio il thread;
}
if (e.actionCommand equals "Ferma Timer") {
setto il flag;
riabilito bottone "Avvia timer";
}
}
...
class MyTask implements Runnable {
run() {
// operazioni fatte eseguire su un altro thread:
implementazione del ciclo di operazioni
// uso del flag per il controllo del ciclo
}
}
Un'alternativa è data dall'uso della classe SwingWorker. Ti linko questa breve guida a Swing, che contiene degli utili chiarimenti alle questioni che stai affrontando (il discorso dell'EDT in particolare, all'inizio; alle ultime pagine trovi un'introduzione all'uso di SwingWorker). Per le questioni sull'uso del multithreading in Java, ti consiglio un buon manuale o comunque una lettura introduttiva dei relativi capitoli nei Java Tutorials che trovi online.
__________________
As long as you are basically literate in programming, you should be able to express any logical relationship you understand. If you don’t understand a logical relationship, you can use the attempt to program it as a means to learn about it. (Chris Crawford) Ultima modifica di banryu79 : 24-03-2010 alle 13:33. |
|
|
|
|
|
#3 |
|
Senior Member
Iscritto dal: Sep 2007
Messaggi: 1071
|
il metodo actionPerformed viene chiamato ed eseguito dentro il thread AWT, i cui compiti sono tra l'altro il repaint dei componenti (ecco perchè non riesci a cliccare sul bottone) e molte altre cose (che non sto qui ad elencare), la cosa che tu fai è eseguire un ciclo che in pratica congela le attività del thread si AWT fino a quando non hai finito la ricarica della finta batteria...
per fare quello che vuoi ti serve un Thread, visto che stai iniziando li hai già studiati? perchè se no puoi utilizzare la classe javax.swing.Timer oppure se il codice lo vuoi eseguire nel metodo actionPerformed usi uno SwingWorker che non ti obbligano a crearti un tuo Thread
__________________
Affari: ariakasneverborne, PanCar, Luk@°°°, Fabio310, kintaro oe, krike, fabry180384, dariox am2, chiadoz, windsofchange, dado1979, Rudyduca, aleforumista, Sheva77 |
|
|
|
|
|
#4 |
|
Junior Member
Iscritto dal: Oct 2008
Messaggi: 29
|
mhmm vi ringrazio molto!!!
Mi metto un pò a studiare la cosa e poi vi aggiorno su quello ke ho fatto... ( speriamo) a presto!
__________________
Toshiba Satellite A300-1GC ,Intel C2D P8400 3Mb L2 1066FBS, 4Gb DDR2, HD320Gb SATA, ATI Mobility Radeon HD3650 |
|
|
|
|
|
#5 | |
|
Junior Member
Iscritto dal: Oct 2008
Messaggi: 29
|
Quote:
in aiutino in più? o posso rinunciare finchè non conoscerò bene java!?
__________________
Toshiba Satellite A300-1GC ,Intel C2D P8400 3Mb L2 1066FBS, 4Gb DDR2, HD320Gb SATA, ATI Mobility Radeon HD3650 Ultima modifica di ciccio5 : 24-03-2010 alle 17:21. |
|
|
|
|
|
|
#6 | |
|
Senior Member
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
|
Quote:
Procedere in modo razionale nell'acquisizione delle competenze invece, è sicuramente una strada percorribile. Magari per il momento solo per quelle strettamente neccessarie per superare questo specifico problema, il che implica capire la natura di alcune situazioni che si sono presentate e investire il tempo neccessario (pochi giorni) per digerirle una prima volta e produrre la soluzione al problema. Prima di tutto, dato che usi Swing e il problema si manifesta a causa della natura single-threaded di Swing/AWT, dovresti capire questo aspetto. Trovi una prima spiegazione nelle primissime pagine del tutorial che ti ho linkato prima (investendo 3 orette, te lo puoi comodamente leggere tutto: se usi Swing non sarà affatto tempo sprecato). Quindi, avendo compreso questo, e la conseguente neccessità di dover implementare una parte della tua funzionalità con un altro thread, potrebbe essere utile leggere qualcosa del supporto che Java in quanto linguaggio offre alla programmazione multithreading, tanto per conoscere le basi-basi (classi Thread, Runnable, keyword syncrhonized, metodi wait() e notify di Object, metodi statici della classe Thread) magari reperendo qualche tutorial online (con Google trovi di tutto, io ti indico l'indice dei Java Tutorial). Quindi affronti il tuo problema: analizzi ciò che ti si para davanti per capire le cose e trovare una soluzione da implementare. Ho cercato di fare proprio questo nel mio post precedente; speravo che le osservazioni unite al pseudo-codice postato potessero esserti utili per darti una traccia, un'idea, farti riflettere. Considera che una volta che hai capito bene una cosa, anche se ti richidede del tempo, poi quella cosa, quei concetti, li ritrovi in diverse salse in vagonate di altri casi, e tu hai dalla tua una base di conoscenza in più utile a fronteggiarli senza tanti patemi, dunque io ti consiglio di investire del tempo nello studio. Poi se hai domande specifiche spara: noi qui (io nel mio piccolo) ti si aiuta, se si può.
__________________
As long as you are basically literate in programming, you should be able to express any logical relationship you understand. If you don’t understand a logical relationship, you can use the attempt to program it as a means to learn about it. (Chris Crawford) |
|
|
|
|
|
|
#7 |
|
Junior Member
Iscritto dal: Oct 2008
Messaggi: 29
|
TI ringrazio tantissimo!!! è che di mio sono molto frettoloso e pensavo che creare un Timer fosse cosa semplice ( ovviamente conoscendo il sistema diventa semplice ) o che comunque nn richiedeva particolari conoscende di Java. Mi metterò sotto, quando ho tempo, nel mio viaggio alla conoscenza di questo fantastico Linguaggio.
E' stato un piacere alla prossima! Perchè di prossime ce ne saranno ! Ahahaha! Saluti
__________________
Toshiba Satellite A300-1GC ,Intel C2D P8400 3Mb L2 1066FBS, 4Gb DDR2, HD320Gb SATA, ATI Mobility Radeon HD3650 |
|
|
|
|
|
#8 | |||
|
Senior Member
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
|
Quote:
Puoi leggere un piccolo tutorial a proposito qui. E qui ci sono i javadoc di questa classe. Poi esiste anche un'altra classe "timer", nel JDK, ed è java.util.Timer. Questa classe è "più generica" della precedente, e soddisfa quindi uno spettro più ampio di necessità, ma presenta anch'essa dei limiti. Qui trovi i javadoc. E qui un articolo che tratta di entrambe. Se invece il tuo scopo, come dicevo prima, è quello i esercitarti, creare un "timer" utilizzando un altro thread può essere fatto in molti modi diversi. Prendendo spunto da quanto hai scritto nel primo post, diciamo che la neccessità in oggetto è quella di definire una classe personalizzata che rappresenta un "countdown". Lo scopo del nostro "countdown" è quello di contare alla rovescia la quantità di "tempo" che gli impostiamo. Deve fare questo in maniera "non bloccante", ovvero il thread in cui viene avviato il countdwon non deve eseguire le operazioni del countdown stesso, altrimenti resterebbe "bloccato" in questa attività invece di procedere ad eseguire le operazioni successive. Per ottenere questo il countdown dovrà essere implementato in modo da usare internamente un suo thread, e, sempre per questo motivo, quando ha finito deve inviare un segnale a tutti coloro che sono interessati (detti ascoltatori) ad ascoltare questo evento (countdown terminato). Quindi il countdown deve avere al suo interno una lista di ascoltatori; deve avere un metodo per registrare gli ascoltatori interessati, per rimuoverli e per notificarli e tutto questo implica anche il fatto che dobbiamo definire una interfaccia che rappresenti un ascoltatore (chiamiamola senza tanta fantasia CountdownListener). Cominciamo implementando questa base; in futuro potremmo aggiungere altre funzionalità, per esempio fare in modo che il "countdown" mandi un segnale a tutti gli ascoltatori registrati ogni tot di tempo, fino a che non termina. Ricapitoliamo: Quote:
Quote:
__________________
As long as you are basically literate in programming, you should be able to express any logical relationship you understand. If you don’t understand a logical relationship, you can use the attempt to program it as a means to learn about it. (Chris Crawford) |
|||
|
|
|
|
|
#9 |
|
Senior Member
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
|
classe Countdown
Codice:
package countdown;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
/**
* Un conto alla rovescia, non bloccante, che notifica tutti gli ascoltatori registrati al passaggio del
* prefissato intervallo di tempo, dall'avvio del countdown.
*
* @author Francesco
*/
public class Countdown
{
final private long DELAY;
final private Runnable COUNTER_THREAD;
// listerns support for countdown events
private Collection<CountdownListener> listeners;
/**
* Construct a countdown that count for delay milliseconds
* @param delay the delay, in millisec
*/
public Countdown(long delay)
{
DELAY = delay;
COUNTER_THREAD = new Counter();
}
/**
* Start the countdown (non-blocking)
*/
public void start()
{
Thread t = new Thread(COUNTER_THREAD);
t.start();
}
/**
* Register l for countdown events.
* @param l the COuntdownListener to be registered.
*/
public void addListener(CountdownListener l)
{
// the listener must not be null
if (l == null) {
return;
}
// init listeners
if (listeners == null) {
listeners = new HashSet<CountdownListener>(10);
}
listeners.add(l);
}
/**
* Deregister all listeners
*/
public void removeAllListeners()
{
Iterator<?> it = listeners.iterator();
while (it.hasNext()) it.remove();
}
protected void notifyListeners(float seconds)
{
Iterator<CountdownListener> it = listeners.iterator();
while (it.hasNext()) {
CountdownListener l = it.next();
l.countdownEnded(seconds);
}
}
/**
* Simple countdown implementation, wait for DELAY millisec.
* If the countdown thread is interrupted immediatly end the countdown and notify all listeners, for
* semplicity.
* Also notify the listeners about the elapsed time.
*/
class Counter implements Runnable
{
public void run() {
long started = System.nanoTime();
try {
Thread.sleep(DELAY);
}
catch(InterruptedException ignored) {
// do nothing
}
finally {
float elapsed = (System.nanoTime()-started)/1000000000f;
notifyListeners(elapsed);
}
}
}
}
Quando viene fatto partire, internamente crea un nuovo Thread a cui passa un Runnable implementato dalla classe interna Counter, che appunto attende (mette a dormire il thread per il tempo specificato) che sia trascorso il lasso di tempo impostato per poi notificare il termine del countdown stesso e il tempo trascorso a tutti gli ascoltatori registrati.
__________________
As long as you are basically literate in programming, you should be able to express any logical relationship you understand. If you don’t understand a logical relationship, you can use the attempt to program it as a means to learn about it. (Chris Crawford) Ultima modifica di banryu79 : 25-03-2010 alle 11:56. |
|
|
|
|
|
#10 |
|
Senior Member
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
|
interfaccia CountdownListener
Codice:
package countdown;
/**
*
* @author Francesco
*/
public interface CountdownListener
{
/**
* Invoked when the countdown ended.
* @param seconds the time elapsed from countdown start, in seconds.
*/
public void countdownEnded(float seconds);
}
Quando il countdown su cui viene registrato termina, verrà invocato il metodo 'countdownEnded'.
__________________
As long as you are basically literate in programming, you should be able to express any logical relationship you understand. If you don’t understand a logical relationship, you can use the attempt to program it as a means to learn about it. (Chris Crawford) Ultima modifica di banryu79 : 25-03-2010 alle 11:56. |
|
|
|
|
|
#11 |
|
Senior Member
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
|
Usiamo il nostro countdown:
Codice:
package countdown;
/**
*
* @author Francesco
*/
public class ConsolleCountdown
{
public static void main(String... args)
{
// creation and listener registration:
Countdown c1 = new Countdown(1000 * 5);
c1.addListener(new CountdownListener() {
public void countdownEnded(float seconds) {
System.out.println("Countdown ended after "+seconds+" sec.");
}
});
System.out.println("Countdown created.");
// execution:
c1.start();
System.out.println("Countdown started!");
System.out.println("I can do other things while c1 is counting.");
System.out.println("For example, I can sleep for 1 sec.");
sleep(1000);
System.out.println("And again...");
sleep(1000);
System.out.println("...and again!");
sleep(1000);
System.out.println("Preatty boring, uh?");
}
private static void sleep(long millis) {
try {
Thread.sleep(millis);
}
catch(InterruptedException ignored) {
// gnam... good taste!
}
}
}
Codice:
...nella classe Countdown
/**
* Start the countdown (non-blocking)
*/
public void start()
{
Thread t = new Thread(COUNTER_THREAD);
t.start();
}
Da notare quindi, che il thread che chiama il metodo dell'ascoltatore countdownEnded() e stampa sullo standard output l'ultimo messaggio ("Countdown ended after XYZ sec.") non è il "thread del main" ma è il "thread del countdown".
__________________
As long as you are basically literate in programming, you should be able to express any logical relationship you understand. If you don’t understand a logical relationship, you can use the attempt to program it as a means to learn about it. (Chris Crawford) Ultima modifica di banryu79 : 25-03-2010 alle 11:56. |
|
|
|
|
|
#12 |
|
Senior Member
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
|
Proviamo a vedere come utilizzare Countdown nel tuo caso, con Swing:
Codice:
public void actionPerformed(ActionEvent e) {
String bottone = e.getActionCommand();
if (bottone.equals("Avvia Timer")) {
long time = Long.parseLong(timer.getText());
Countdown counter = new Countdown(time);
counter.addListener(new CountdownListener(){
public void countdownEnded(float seconds) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
carica.setText("CARICA COMPLETATA !!!");
}
});
}
});
carica.setText("BATTERIA IN CARICA...");
counter.start();
}
if (bottone.equals("Ferma Timer")) {
//carica.setText("CARICA COMPLETATA !!!");
JOptionPane.showMessageDialog(null, "Funzionalita' non ancora supportata");
}
}
Dato che il thread che chiamerà il metodo countdownEnded come abbiamo visto è il thread creato da Countdown e non l'EDT, normalmente non potrei eseguire chiamate a metodi di componenti grafici dell'interfaccia utente (perchè appunto DEVE essere l'EDT a eseguire queste operazioni) e dovrei usare l'escamotage che vedi nel codice qui sopra (incapsulare le operazioni che devono essere fatte eseguire dall'EDT in un Runnable, e passare quest'ultimo al metodo invokeLater della classe SwingUtilities che si preoccupa di inserire il Runnable nella coda degli eventi di Swing). Fortunatamente ci sono alcune (pochissime) operazioni che possono essere invocate anche da altri thread; il metodo setText di tutti i JTextComponent è una di queste (è un metodo cosidetto thread-safe). Quindi il codice sopra diventa questo: Codice:
public void actionPerformed(ActionEvent e) {
String bottone = e.getActionCommand();
if (bottone.equals("Avvia Timer")) {
long time = Long.parseLong(timer.getText());
Countdown counter = new Countdown(time);
counter.addListener(new CountdownListener(){
public void countdownEnded(float seconds) {
carica.setText("CARICA COMPLETATA !!!");
}
});
carica.setText("BATTERIA IN CARICA...");
counter.start();
}
if (bottone.equals("Ferma Timer")) {
//carica.setText("CARICA COMPLETATA !!!");
JOptionPane.showMessageDialog(null, "Funzionalita' non ancora supportata");
}
}
__________________
As long as you are basically literate in programming, you should be able to express any logical relationship you understand. If you don’t understand a logical relationship, you can use the attempt to program it as a means to learn about it. (Chris Crawford) Ultima modifica di banryu79 : 25-03-2010 alle 12:21. |
|
|
|
|
|
#13 |
|
Junior Member
Iscritto dal: Oct 2008
Messaggi: 29
|
OMG!
Noto con piacere e paura che ho parecchia strada da fare ancora! Ho letto ed importato nel mio progetto, che sto odiando Spiego quello che ho capito, hai implementato : - la classe Countdown, al cui interno vi sono dei metodi che gestiscono rispettivamente : start , creazione dei Listener, rimozione dei Listener e l'evento di notifica; - la classe Counter per quanto riguarda il Runnable, che penso effettua appunto il conteggio alla rovescia del tempo in millisecondi che gli viene passato dalla variabile DELAY; In pratica il ciclo dovrebbe essere questo : - metto i dati, (tempo in millisecondi nella famosa JTextArea "timer") - Schiaccio il pulsante Avvia Timer, - crea una variabile di tipo long e vi mette dentro il tempo presente in "timer", - crea una variabile di tipo Countdown e gli passa il dato contenuto nella variabile di tipo long time, dove all interno del metodo la imposta a DELAY, - crea il listener ovvero quello su cui accadrà l'evento cioè il "countdownEnded" che viene invocato a fine countdown e che cambia la scritta della Jlabel in CARICA COMPLETATA !!! ( ovviamente questo succede solo quando il countdown è finito, perchè è lì che viene invocato il "countdownEnded" ) - mette la scritta della JLabel in BATTERIA IN CARICA... , - fa partire il conteggio. ( ance se non ho ben capito come ) Spero che sia, non dico giusto, ma si avvicina a quello che fa. Ho notato che hai messo il messaggio "Funzionalita' non ancora supportata" per quanto riguarda il tasto Ferma Timer, e se volessi fermare il countdown ? non si potrebbe implementare un altro metodo come quello dello start() che blocchi il countdown ??? Mi rendo conto che sono una palla al piede ! GRAZIE VERAMENTE PER IL TEMPO CHE TI STO FACENDO PERDERE !
__________________
Toshiba Satellite A300-1GC ,Intel C2D P8400 3Mb L2 1066FBS, 4Gb DDR2, HD320Gb SATA, ATI Mobility Radeon HD3650 |
|
|
|
|
|
#14 | |||
|
Senior Member
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
|
Quote:
Quote:
Quote:
Una soluzione che richieda modifiche minimali all'implementazione di sopra e aggiunga il supporto all'interruzione del countdown potrebbe essere realizzata sfruttando il meccanismo di "interrupt" della classe Thread. Per capire la cosa dovresti prima conoscere questo meccanismo. Per brevità ti dico solo che la classe Thread ha al suo interno un flag che viene settato quando un thread riceve un interrupt. Quando poi l'interrupt viene gestito, il flag viene resettato. Invocare il metodo interrupt() su un'istanza di Thread, significa appunto segnalare a quell'istanza una "richiesta" di interruzione. Dico richiesta, perchè il thread in questione deve supportare in qualche modo il fatto di poter essere interrotto, altrimenti ciccia. Cioè, nel flusso di esecuzione che il thread stesso esegue, deve esistere la gestione di un'eventuale interruzione. Dato che il flusso di esecuzione di un thread inizia con il codice contenuto nel metodo run di quel Thread, è nel corpo del metodo run che, in punti/momenti opportuni vanno gestite le interruzioni. Nel prossimo post ti faccio l'esempio di come supportare l'interruzione di un thread che esegue un semplice ciclo infinito, in due modi diversi. Poi ti mostro come supportare l'interruzione nel nostro thread Countdown. Posto a rate perchè oggi a lavoro ho una giornata un pelo più vispa di ieri (che invece era calma piatta). Non vedo perchè, non sono mica costretto a risponderti ne ad aiutarti, lo faccio perchè mi piace.
__________________
As long as you are basically literate in programming, you should be able to express any logical relationship you understand. If you don’t understand a logical relationship, you can use the attempt to program it as a means to learn about it. (Chris Crawford) |
|||
|
|
|
|
|
#15 | |||||||||
|
Junior Member
Iscritto dal: Oct 2008
Messaggi: 29
|
Buongiorno,
spero che la giornata sia iniziata abbastanza bene. Continuo a ringraziarti e non mi stancherò mai di farlo, per il piacere, al quanto pare di entrambi, ed al tempo impegnato per aiutarmi a comprendere questo meraviglioso linguaggio. Sono felice di aver capito quello che hai fatto prima, il che vuol dire che non sono tanto bloccato di cervello ehehehehe ! Proviamo ad andare avanti Vediamo se ho capito da quello che ho letto : bisogna implementare un altro metodo nella classe Countdown, simile a quella dello start, però per l' interrupt() e per fare questo bisogna : - aggiungere un altra variabile nella classe Countdown oltre a queste : Quote:
Quote:
Quote:
Quote:
poi implementare il metodo interrupt() così : Quote:
Andiamo alla gestione dei bottoni, ovvero nell'actionPerformed: -inizializzo una variabile esterna al controllo se i singoli tasti sono attivati; Quote:
Quote:
Quote:
- le operazione da svolgere quando si preme "Ferma Timer", saranno : Quote:
Ti auguro buona giornata!
__________________
Toshiba Satellite A300-1GC ,Intel C2D P8400 3Mb L2 1066FBS, 4Gb DDR2, HD320Gb SATA, ATI Mobility Radeon HD3650 |
|||||||||
|
|
|
|
|
#16 |
|
Senior Member
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
|
Supportare l'interruzione di un Thread
Primo passo: definimo a mo di esempio un thread "ciuccia CPU". Un thread "ciuccia CPU" è un thread che gira in loop continuo senza fare nulla di utile; in pratica una pura ciofeca, eccolo qua:
Codice:
public class CiofecaTread extends Thread
{
@Override
public void run()
{
System.out.println("<Thread>loop started.");
while (true) {
// magia: ciuccia la CPU facendo assolutamente niente
// tranne girare come un criceto impazzito nella sua ruota.
}
// istruzione irraggiungibile:
// System.out.println("<Thread>loop ended.");
}
public static void main(String... args) {
CiofecaTread t = new CiofecaTread();
t.start();
System.out.println("<Main>thread launched!");
System.out.println("<Main>sleeping...");
}
}
1) non si controlla mai se il flag di interrupt del thread è stato settato (cosa che accadrebbe se nel main come ultima istruzione aggiungessi una chiamata al metodo interrupt() del thread) per gestire l'eventuale interruzione; 2) non si fa uso di nessun metodo della classe Thread che lanci l'eccezione InterruptedException (come ad esempio Thread.sleep) e costringa a gestirla in un blocco try-catch dove è possibile supportare l'interruzione; 3) non si fa neppure uso di nessuna varibile di 'flag' per controllare la condizione del ciclo, e avere così la possibilità di terminarlo. Proviamo ora a supportare l'interruzione con la tecnica descritta al punto (3). Usiamo un semplice boolean come flag, che faccia da condizione per il ciclo. Il metodo run di Thread è stato sovvrascritto nella nostra classe CiofecaTread per eseguire il ciclo "infinito". Potremmo quindi sovvrascrivere il metodo interrupt nella nostra classe per settare il nostro flag a false, provocando quindi la terminazione del ciclo. (In marroncino le modifiche rispetto al precedente codice di CiofecaThread) Codice:
public class IterruptibleThread extends Thread
{
private boolean runFlag = true;
@Override
public void run()
{
System.out.println("<Thread>loop started.");
while (runFlag) {
// magia: ciuccia la CPU facendo assolutamente niente
// tranne girare come un criceto impazzito nella sua ruota.
}
// istruzione ora raggiungibile:
System.out.println("<Thread>loop ended.");
}
@Override
public void interrupt()
{
// prima chiamiamo interrupt della classe padre, Thread
// per lasciare inalterato il suo comportamento
super.interrupt();
// quindi settiamo il flag per terminare il ciclo
runFlag = false;
}
public static void main(String... args) {
IterruptibleThread t = new IterruptibleThread();
t.start();
System.out.println("<Main>thread launched!");
System.out.println("<Main>sleeping...");
sleep(3000);
System.out.println("<Main>sending interrupt...");
t.interrupt();
}
public static void sleep(long millis)
{
try {
Thread.sleep(millis);
}
catch (InterruptedException ignored) {/*do nothing*/}
}
}
__________________
As long as you are basically literate in programming, you should be able to express any logical relationship you understand. If you don’t understand a logical relationship, you can use the attempt to program it as a means to learn about it. (Chris Crawford) Ultima modifica di banryu79 : 26-03-2010 alle 13:24. Motivo: refuso |
|
|
|
|
|
#17 |
|
Senior Member
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
|
Altro esempio...
Proviamo ora a supportare l'interruzione con la tecnica descritta al punto (1), cioè sfruttando il meccanismo di interrupt che la classe Thread ci mette già a disposizione (invece di definire noi un nostro flag, sfruttiamo il flag interno per gli interrupt di Thread).
L'idea è quella di controllare se è arrivato un interrupt (come al solito, provocato da una chiamata al meotdo interrupt) andando a vedere se il flag interno è stato settato. Thread è una classe che mette già a disposizione dei metodi per interrogare lo stato di questo flag ed eventualmente resettarlo. Ad esempio, il metodo statico Thread.interrupted() torna true se il thread corrente (quello che esegue la chiamta Thread.interrupted()) ha ricevuto una richiesta di interruzione, e resetta automaticamente il flag. Nel nostro caso, possiamo usare questa possibilità di controllo&reset del flag di interrupt per condizionare l'esecuzione del ciclo while: (le parti rilevanti sono in marroncino) Codice:
public class InterruptibleThread2 extends Thread
{
@Override
public void run()
{
System.out.println("<Thread>loop started.");
while (! Thread.interrupted()) {
// magia: ciuccia la CPU facendo assolutamente niente
// tranne girare come un criceto impazzito nella sua ruota.
}
// istruzione ora raggiungibile:
System.out.println("<Thread>loop ended.");
}
public static void main(String... args) {
InterruptibleThread2 t = new InterruptibleThread2();
t.start();
System.out.println("<Main>thread launched!");
System.out.println("<Main>sleeping...");
sleep(3000);
System.out.println("<Main>sending interrupt...");
t.interrupt();
}
public static void sleep(long millis)
{
try {
Thread.sleep(millis);
}
catch (InterruptedException ignored) {/*do nothing*/}
}
}
__________________
As long as you are basically literate in programming, you should be able to express any logical relationship you understand. If you don’t understand a logical relationship, you can use the attempt to program it as a means to learn about it. (Chris Crawford) Ultima modifica di banryu79 : 26-03-2010 alle 12:18. |
|
|
|
|
|
#18 |
|
Senior Member
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
|
Ultimo esempio su cui riflettere, il caso (2).
Quello, cioè, in cui si supporta l'interruzione di un thread durante la chiamata a un metodo che potrebbe lanciare una InterruptedException: Codice:
package countdown;
public class InterruptibleThread3 extends Thread
{
@Override
public void run()
{
System.out.println("<Thread> started.");
try {
Thread.sleep(150000);
}
catch (InterruptedException ie) {
System.out.println("<Thread> interrupted!");
}
finally {
System.out.println("<Thread> ended.");
}
}
public static void main(String... args) {
InterruptibleThread3 t = new InterruptibleThread3();
t.start();
System.out.println("<Main> thread 't' launched!");
System.out.println("<Main> sleeping...");
sleep(3000);
System.out.println("<Main> sending interrupt to 't'");
t.interrupt();
}
public static void sleep(long millis)
{
try {
Thread.sleep(millis);
}
catch (InterruptedException ignored) {/*do nothing*/}
}
}
Nel frattempo potrebbe arrivargli un'interrupt: in tale caso il metodo sleep spara una InterruptedException e si può quindi gestire l'interrupt nella relativa clausola catch. Facciamo ora un esempio un po' più articolato. Supponiamo che il nostro thread debba eseguire due diverse operazioni, una che richiede un certo tempo (tramite metodo Thread.sleep) e subito dopo un'altra, che è un loop infinito. Naturalmente vogliamo che il nostro thread supporti gli interrupt. Deve quindi supportare le interruzioni sia durante l'esecuzione della prima operazione, che durante la seconda. Dunque ecco una versione provvisoria, che usiamo per studiare la situazione, del metodo run: Codice:
public class InterruptibleThread4 extends Thread
{
@Override
public void run()
{
System.out.println("<Thread> started.");
System.out.println("<Thread> operation_1");
try {
Thread.sleep(7000);
}
catch (InterruptedException ie) {
System.out.println("<Thread> interrupted!");
return;
}
System.out.println("<Thread> operation_2");
while (true) {
// ciclo infinito
if (Thread.interrupted()) {
System.out.println("<Thread> interrupted!");
return;
}
}
}
...
}
Il fatto è che se si vuole supportare l'interrupt per una data operazione, il codice per farlo sembra "assumere due diverse forme": un blocco try-catch in un caso, un controllo esplicito del flag di interrupt del Thread in una condizione di un controllo di flusso che ne gestisce l'interrupt, nell'altro. Sarebbe bello poter gestire la cosa in un unico modo, e magari evitare le duplicazioni di codice di gestione dell'interrupt (in corsivo, nel codice). Se incapsuliamo la seconda operazione (il ciclo "infinito") in un metodo che lancia una InterruptedException, il gioco è fatto perchè possiamo, nel metodo run, utilizzare un unico blocco try-catch per gestire tutte le operazioni. Per uniformità incapsuliamo in un metodo analogo anche la chiamata a Thread.sleep(). Il risultato è questo: Codice:
package countdown;
public class InterruptibleThread4 extends Thread
{
@Override
public void run()
{
System.out.println("<Thread> started.");
try {
operation1();
operation2();
}
catch (InterruptedException ie) {
System.out.println("<Thread> interrupted!");
}
finally {
System.out.println("<Thread> ended.");
}
}
private void operation1() throws InterruptedException
{
System.out.println("<Thread> operation_1, start.");
Thread.sleep(4000);
System.out.println("<Thread> operation_1, end.");
}
private void operation2() throws InterruptedException
{
System.out.println("<Thread> operation_2, infinite...");
while(true) {
// ciclo infinito
if (Thread.interrupted())
throw new InterruptedException();
}
}
public static void main(String... args) {
InterruptibleThread4 t = new InterruptibleThread4();
t.start();
System.out.println("<Main> thread 't' launched!");
System.out.println("<Main> sleeping...");
sleep(8500);
System.out.println("<Main> sending interrupt to 't'");
t.interrupt();
}
public static void sleep(long millis)
{
try {
Thread.sleep(millis);
}
catch (InterruptedException ignored) {/*do nothing*/}
}
}
__________________
As long as you are basically literate in programming, you should be able to express any logical relationship you understand. If you don’t understand a logical relationship, you can use the attempt to program it as a means to learn about it. (Chris Crawford) |
|
|
|
|
|
#19 |
|
Senior Member
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
|
Fammi sapere se riesci a digerire tutto l'ambaradam qui sopra o se ci sono cose che ti risultano poco chiare, mi rendo conto che potrebbero esserci diversi aspetti da chiarire, e resto a disposizione.
In teoria, a digestione compiuta, dovresti essere in grado di poter valutare autonomamente come supportare l'interrupt nella classe Counter, in Countdown (lasciando perdere le questioni relative all'interfaccia grafica, e considerando solo la classe che implementa il countdown). Metto le mani avanti a mia discolpa: non essendo un insegnante ne sapendo nulla di didattica non so se ti sto dando una mano o in effetti se ti sto incasinando...
__________________
As long as you are basically literate in programming, you should be able to express any logical relationship you understand. If you don’t understand a logical relationship, you can use the attempt to program it as a means to learn about it. (Chris Crawford) |
|
|
|
|
|
#20 |
|
Junior Member
Iscritto dal: Oct 2008
Messaggi: 29
|
Ti ringrazio per l ennesima volta.
Per ora non sono molto presente a casa per problemi di università, ma ben presto mi metterò a lavorare al progetto. Se ci riesco o se ho problemi ti avviso! A presto ! Buon fine settimana!
__________________
Toshiba Satellite A300-1GC ,Intel C2D P8400 3Mb L2 1066FBS, 4Gb DDR2, HD320Gb SATA, ATI Mobility Radeon HD3650 |
|
|
|
|
| Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 22:51.



















