View Full Version : [JAVA]Come blocco un thread?
Ho un thread in stato di runnable, devo fare in modo però che dopo aver eseguito il codice del metodo run() si fermi fino a quando non glielo dico io, cioè vorrei avere la possibilità di sospendere il thread e risvegliarlo quando mi pare.
Quello che potrebbe fare al caso mio è yeld() ma non va bene perchè non ho altri thread a cui passare il comando...non esiste un modo per bloccare un thread?
Ovviamente questo non va bene:
Thread t =new Thread(){
public void run(){
while(true){
if(ok){
...esegui codice...
}
}
}
};
Per il semplice motivo che mi spreca troppe risorse e poi è anche brutto come metodo... Ma quello che voglio ottenere è proprio quello.
Ho fatto del casino forse, allora vorrei fare una cosa del genere:
Thread t =new Thread(){
public void run(){
...esegui codice...
sospendi(); //sospende il thread finchè non viene risvegliato
}
};
public void risveglia(){
...codice... //fa rieseguire il metodo run()
}
E' fattibile?
The3DProgrammer
28-07-2006, 16:17
Ho un thread in stato di runnable, devo fare in modo però che dopo aver eseguito il codice del metodo run() si fermi fino a quando non glielo dico io, cioè vorrei avere la possibilità di sospendere il thread e risvegliarlo quando mi pare.
Quello che potrebbe fare al caso mio è yeld() ma non va bene perchè non ho altri thread a cui passare il comando...non esiste un modo per bloccare un thread?
Ovviamente questo non va bene:
Thread t =new Thread(){
public void run(){
while(true){
if(ok){
...esegui codice...
}
}
}
};
Per il semplice motivo che mi spreca troppe risorse e poi è anche brutto come metodo... Ma quello che voglio ottenere è proprio quello.
Thread t =new Thread(){
private Object monitor=new Object();
private bool suspended=false;
public void suspend(){ suspended = true;}
public void notify(){ suspended = false; monitor.notify();}
public void run(){
while(true){
if(suspended){
try{
monitor.wait();
}catch(InterruptedException ecxeption){
...
}
}
...esegui codice...
}
}
};
ciao
Ti ringrazio, non sapevo della possibilità di usare un oggetto in questo modo!
Grazie!
Mi solleva l'eccezzione "current thread not owner", per quale motivo?
The3DProgrammer
28-07-2006, 17:09
Mi solleva l'eccezzione "current thread not owner", per quale motivo?
spe su quale riga?
sono un po intontito (appena svegliato) quindi sicuramente ho scordato qualkosa ;)
The3DProgrammer
28-07-2006, 17:15
ma ke kakkio ho scritto :doh: :D
aspe che ti posto la versione corretta.... :stordita:
:fagiano: :D no problem! :p
Ho trovato questa che fa uso di syncronized:
// Create and start the thread
MyThread thread = new MyThread();
thread.start();
while (true) {
// Do work
// Pause the thread
synchronized (thread) {
thread.pleaseWait = true;
}
// Do work
// Resume the thread
synchronized (thread) {
thread.pleaseWait = false;
thread.notify();
}
// Do work
}
class MyThread extends Thread {
boolean pleaseWait = false;
// This method is called when the thread runs
public void run() {
while (true) {
// Do work
// Check if should wait
synchronized (this) {
while (pleaseWait) {
try {
wait();
} catch (Exception e) {
}
}
}
// Do work
}
}
}
The3DProgrammer
28-07-2006, 17:25
infatti:D
devi semplicemente mettere le chiamate a wait() e notify() tra 2 blokki synchronized(monitor) altrimenti come diventa il thread owner del monitor?:muro: :D Quella postata da te è praticamente come la mia, solo che usa come oggetto monitor il thread stesso. Personalmente nn mi piace come scelta, anche se perfettamente leggittima (se espliciti l'oggetto monitor diventa + chiaro IMHO)
ciao e scusa, la sonnolenza fa brutti skerzi;)
The3DProgrammer
28-07-2006, 17:28
Thread t =new Thread(){
private Object monitor=new Object();
private bool suspended=false;
public void suspend(){ suspended = true;}
public void notify(){
suspended = false;
synchronized(monitor){
monitor.notify();
}
}
public void run(){
while(true){
if(suspended){
try{
synchronized(monitor){
monitor.wait();
}
}catch(InterruptedException ecxeption){
...
}
}
...esegui codice...
}
}
};
Quel suspended deve essere volatile o il suo valore deve essere mutato all'interno di un blocco sincronizzato altrimenti non c'è garanzia che il valore di suspended letto dal Thread in attesa al momento del risveglio sia l'ultimo valore immesso da un Thread concorrente.
Thread t =new Thread(){
private Lock monitor=new ReentrantLock();
private boolean suspended=false;
private Condition wait = monitor.newCondition();
public void suspend(){
monitor.lock();
try {
suspended = true;
} finally {
monitor.unlock();
}
}
public void notify(){
monitor.lock();
try {
suspended = false;
wait.signal();
} finally {
monitor.unlock();
}
}
public void run(){
while(true){
monitor.lock();
try {
while (suspendend)
wait.await();
}catch(InterruptedException ecxeption){
...
} finally {
monitor.unlock();
}
...esegui codice...
}
}
};
P.S: Java 1.5 only
The3DProgrammer
29-07-2006, 12:19
Quel suspended deve essere volatile o il suo valore deve essere mutato all'interno di un blocco sincronizzato altrimenti non c'è garanzia che il valore di suspended letto dal Thread in attesa al momento del risveglio sia l'ultimo valore immesso da un Thread concorrente.
hai perfettamente ragione. suspended è una variabile a cui si accede in concorrenza, per cui deve essere inserita in un blocco synchronized. In questo caso basta rendere synchronized i metodi suspend e notify (che tra l'altro come nomi di metodi nn vanno bene xkè significherebbe overriding di metodi final, ero proprio intronato ieri :D) ed inserire l'accesso in run alla variabile suspended in un blocco synchronized(this).
ciauz
...ed inserire l'accesso in run alla variabile suspended in un blocco synchronized(this).
ciauz
Ovvero?
Ho fatto così:
synchronized(controllo){
synchronized(this){
if(sospeso){
try{
controllo.wait();
}
catch(InterruptedException e){System.out.println(e);}
}
}
}
Ma ora non funziona più, il thread non si risveglia, come devo fare?
The3DProgrammer
29-07-2006, 14:39
Ho fatto così:
synchronized(controllo){
synchronized(this){
if(sospeso){
try{
controllo.wait();
}
catch(InterruptedException e){System.out.println(e);}
}
}
}
Ma ora non funziona più, il thread non si risveglia, come devo fare?
così nn si sveglia + xkè il thread, entrando in wait, rilascia la ownership sul monitor controllo ma nn sull'altro (this) cosa che provoca l'impossibilità di accedere a controllo.notify() da parte degli altri thread concorrenti. Dovresti fare una cosa del genere:
[CODE]
while(true){
boolean mustWait=false;
synchronized(this){
mustWait=sospeso;
}
if(mustWait){
synchronized(controllo){
try{
controllo.wait();
}
catch(InterruptedException e){System.out.println(e);}
}
}
}
a questo punto xò questa implementazione comincia a nn 'piacermi + (1 solo monitor è + ke sufficiente a realizzare una cosa del genere, complicare il codice con troppe strutture di sincronizzazione in ambito multithread è sempre male;)) per cui potresti usare l'implementazione che hai trovato sul web (che usa l'oggetto thread stesso come monitor), o quella ke ha postato cisc
ciauz;)
The3DProgrammer
29-07-2006, 14:47
ora che guardo bene anche quella ke hai postato xò elimina quegli abberranti
synchronized(thread){
thread.pleaseWait=x;
}
e metti 2 metodi synchronized, ma soprattutto metti pleaseWait privata :D :p
ciau
Ma forse io nn ho capito bene che tipo di problema mi darebbe il codice postato all'inizio? io ora sto usando il tuo, con solo la modifica dei metodi supspend e notify che li ho messi synchronized.
The3DProgrammer
29-07-2006, 15:14
Ma forse io nn ho capito bene che tipo di problema mi darebbe il codice postato all'inizio? io ora sto usando il tuo, con solo la modifica dei metodi supspend e notify che li ho messi synchronized.
L'accesso alla variabile suspended deve essere obbligatoriamente sincronizzato, in quanto può essere potenzialmente modificata contemporaneamente da thread concorrenti. Potrebbe essere che il controllo sulla variabile suspended porti a non leggere effettivamente l'ultimo valore scritto (si chiama race condition, probabilmente ti viene difficile capire il problema perchè l'informazione condivisa è una variabile booleana, ma pensa ad es. ad un intero che rappresenti un conto in banca e che viene acceduto da 3 thread senza sincronizzazione). Di conseguenza è necessario implementare un meccanismo di mutua esclusione che garantisca la sequenzialità delle operazioni effettuate sulla variabile suspended, in modo che solo un thread alla volta possa accedervi. Se metti synchronized solo su supend() e notify() hai la sicurezza che richieste di sospensione e di risveglio avvengano sequenzialmente, ma non sei sicuro che avvenga una chiamata suspend() mentre in run() si sta controllando il valore della variabile suspended, il che significa che potresti ritrovare il thread sospeso anche se nn era questa l'intenzione, o il thread in esecuzione anche se tu lo volevi sospeso. Garantendo la sequenzialità delle operazioni su suspended questo non avviene.
Ciauz
Io la sapevo in modo diverso.
Secondo le specifiche del linguaggio di programmazione Java, ogni Thread lavora su copie delle variabili residenti nell'heap. Quando un Thread modifica il valore di un campo modifica innanzitutto la copia interna di quel valore. Modifica anche il valore contenuto nell'heap? Il linguaggio ci dice che è libero di non farlo.
Detto altrimenti, supponendo che A e B siano due Thread, è perfettamente lecito quanto segue:
A legge il valore di suspended dall'heap e ottiene false.
B legge il valore di suspended dall'heap e ottiene false.
A cambia il valore di suspended in true
B legge il valore di suspended dall'heap e ottiene false.
Questo perchè A deve cambiare il valore interno di suspended ma non il valore "originale".
Nel caso in cui il campo sia volatile o se la scrittura avvenga in un blocco sincronizzato allora il modello di memoria stabilisce esplicitamente che la mutazione deva coinvolgere anche la regione di memoria condivisa.
Io la sapevo in modo diverso.
Secondo le specifiche del linguaggio di programmazione Java, ogni Thread lavora su copie delle variabili residenti nell'heap. Quando un Thread modifica il valore di un campo modifica innanzitutto la copia interna di quel valore. Modifica anche il valore contenuto nell'heap? Il linguaggio ci dice che è libero di non farlo.
Detto altrimenti, supponendo che A e B siano due Thread, è perfettamente lecito quanto segue:
A legge il valore di suspended dall'heap e ottiene false.
B legge il valore di suspended dall'heap e ottiene false.
A cambia il valore di suspended in true
B legge il valore di suspended dall'heap e ottiene false.
Questo perchè A deve cambiare il valore interno di suspended ma non il valore "originale".
Nel caso in cui il campo sia volatile o se la scrittura avvenga in un blocco sincronizzato allora il modello di memoria stabilisce esplicitamente che la mutazione deva coinvolgere anche la regione di memoria condivisa.
questo comportamento mi è nuovo, e mi sembra anche abbastanza inefficiente...io sono a conoscenza del comportamento esposto da The3dProgrammer, dell'interleaved e della race condition
Bho ma parlate tanto difficile che fatico un po' a seguirvi.
Comunque considerando che mi sono fatto una classe ThreadDiServizio il quale estende Thread è "più o meno" il codice di The3DProgrammer(quello che funziona si intende :D) ogni oggetto istanziato di queesta classe ha il suo ogetto monitor che tocca solo lui o sbaglio? dove sta il problema?
Capitolo 17 sezione 4 delle specifiche del linguaggio di programmazione Java.
The3DProgrammer
29-07-2006, 20:40
Capitolo 17 sezione 4 delle specifiche del linguaggio di programmazione Java.
caspita, non avrei mai pensato che java riservasse una sorpresa del genere. Ho sempre usato i monitor ragionando in funzione delle classiche race conditions (il mio linguaggio di riferimento è il C++, programmo in java solo per hobby o quando mi assegnano qualke lavoro) e ignoravo completamente un memory model del genere. Credo che in poki lo conoscano cmq :). Cmq a parte gli skerzi, dando un'okkiata al testo che hai indicato (in particolare quel capitolo è molto interessante e con un discreto utilizzo di formalismi, merita sicuramente uno studio + approfondito) mi è parso di capire che la variabile condivisa viene modificata in queste eventualità:
-quando un thread termina
-quando rilascia un lock
-se la variabile è volatile
xò nel programma che ho scritto per testare la classe di memon (la seconda versione, quella senza blokki synchronized) che comprendeva semplicemente un while(true) nel main() in cui ad ogni iterazione richiedevo all'utente l'azione da intraprendere sul thread (suspend/resume) mentre il thread era in esecuzione tutto funzionava correttamente pur non rispettando nessuna di quei 3 vincoli. Perkè?
grazie delle info cmq ;)
Le specifiche del linguaggio trattano l'argomento fornendo delle regole minime di comportamento. Nei casi indicati (ne esiste almeno un quarto, l'inizializzazione al valore di default di un campo è sempre visibile alla lettura successiva) le modifiche apportate da un Thread al valore di una variabile condivisa (tra Thread) precedono altre operazioni che coinvolgano quel valore.
Io vedo due possibili ragioni per cui il codice incollato può dare il risultato atteso pur non rispettando le norme del linguaggio. La prima, poco probabile ma possibile, è che la corrispondenza sia accidentale: di solito si dice che l'interazione tra due o più flussi di esecuzione concorrenti è indeterministica quindi è possibile che tutto vada a schifio (termine tecnico) così come che tutto vada a gonfie vele.
La seconda, per cui propenderei, è che la concreta versione del linguaggio adottata nella piattaforma Java SE di Sun, rispetti, come è necessario, le garanzie minime previste nelle specifiche del linguaggio, e ne introduca altre, individualmente o come conseguenza necessaria di altri meccanismi.
Lo dico in "ipotesi ragionevole" perchè non ho mai letto documenti riguardanti la concreta realizzazione del contenuto di quelle parti delle specifiche da parte di Sun piuttosto che di Bea o chi altri. Credo che spulciando i contenuti di Mustang si possa stabilire se le cose stiano effettivamente così ma non l'ho mai fatto.
La suddetta variabile suspended di tipo boolean non e' condivisa,
quindi non capisco come cio' possa portare a problemi
(l'assegnamento a valori primitivi non a 64 bit e' atomico)
suspended è un campo, i campi stanno nell'heap e l'heap è per definizione la regione di memoria condivisa tra Thread.
Scusa, ma secondo il codice di prima:
Thread t = new Thread() {
private Object monitor = new Object();
private boolean suspended = false;
...
in ogni momento un thread ha la sua variabile 'suspended' privata e locale -
nel senso che non e' condivisa con altri thread - a cui solo lui puo' accedere.
Quindi la differenza tra volatile e non in questo caso non c'e'...
o no?
The3DProgrammer
30-07-2006, 17:37
Scusa, ma secondo il codice di prima:
Thread t = new Thread() {
private Object monitor = new Object();
private boolean suspended = false;
...
in ogni momento un thread ha la sua variabile 'suspended' privata e locale -
nel senso che non e' condivisa con altri thread - a cui solo lui puo' accedere.
Quindi la differenza tra volatile e non in questo caso non c'e'...
o no?
credo si sia fatta confusione (x questo Memon nn ha capito dove sta il problema) perkè l'oggetto è una anonymous class. Quando parlavamo di thread io e PGI-Bis nn intendevamo thread come istanza della classe anonymous definita ma nella sua accezione classica, cioè come flusso parallelo di esecuzione. Ti faccio un esempio. Mentre il run() definito nella classe anonymous è in esecuzione, un altro thread (x es. il primary thread che esegue il main()) potrebbe andare a modificare il valore di suspended tramite chiamata a suspend().
ad es.
public static void main(String args[]){
Thread t=new Thread(){ ... }
t.start();
t.suspend();
.... etc etc
}
il memory consistency model di java ci dice che il run() di t in esecuzione potrebbe nn vedere la modifica alla variabile suspended (come diceva PGI-bis non c'è garanzia che il valore effettivamente condiviso venga poi modificato). Non è quindi un problema di variabili condivise tra oggetti (in quanto ogni istanza della anonymous avrà effettivamente un proprio campo suspended come correttamente dici) ma un problema di accesso alla variabile suspended da + thread in esecuzione in parallelo.
ciao
Thread t = new Thread() {
private Object monitor = new Object();
private boolean suspended = false;
...
suspended non è locale, è un campo di una classe locale. Quella variabile è condivisa o, meglio, sta in una regione di memoria condivisa da più Thread. E' private, dunque non è accessibile ma è un'altra storia.
suspend() consente (nelle intenzioni di chi l'ha scritto) ad un Thread diverso di modificare la variabile suspended. Altri Thread vedranno quelle modifiche? Direi di no, stando al memory model ufficiale.
The3DProgrammer
30-07-2006, 17:48
bingo!
ho trovato un caso in cui il codice di prima nn funziona. Mettendo il codice che ho usato per testare la classe postata (senza synchronized) in un altro thread (non nel main()) il thread si sospende, ma nn si risveglia. Incredibile!!!
erano meglio le klassike race conditions:D
ciao
Allora giusto per sapere, questo codice così come lo scritto va bene o incappa nello stesso errore?
public abstract class ThreadDiServizio extends Thread{
private boolean sospeso=true,avviato=true;
public ThreadDiServizio(String s){
super(s);
}
public synchronized void sospendi(){
sospeso=true;
}
public synchronized void risveglia(){
sospeso=false;
notify();
}
public void chiudi(){
avviato=false;
risveglia();
}
public void run(){
inizializza(); //Codice eseguito solo all'avvio del servizio
while(avviato){
synchronized(this){
if(sospeso){
try{
wait();
}
catch(InterruptedException e){
System.out.println(e);
}
}
}
esegui(); //E' il compito del servizio
}
chiusura();
}
public abstract void esegui();
public abstract void chiusura();
public abstract void inizializza();
}
The3DProgrammer
30-07-2006, 20:13
guarda ad okkio sembrerebbe corretto per la variabile sospeso, ma lo stesso problema che prima era sulla variabile sospeso adesso lo ritrovi sulla variabile avviato :)
Tra l'altro nella classe che hai scritto noto un piccolo problema di design. Hai reso ThreadDiServizio una classe astratta con 3 metodi astratti. Guardando questi tre metodi nn si può fare a meno di notare alcune cose:
1) Con questi metodi darai ad ogni sottoclasse di ThreadDiServizio 2 responsabilità (gestione del servizio e del loop di esecuzione) il che viola il principio di singola responsabilità
2) Ogni volta che dovrai implementare una nuovo servizio dovrai ereditare da ThreadDiServizio con nuovi metodi esegui, inizializza e chiudi
ti viene in aiuto il pattern command (opportunamente adattato alle tue esigenze):
interface Servizio{
public void inizializza();
public void esegui();
public void chiudi();
}
public class ThreadDiServizio extends Thread{
private boolean sospeso=true,avviato=true;
private Servizio servizio;
public ThreadDiServizio(String s,Servizio servizio){
super(s);
this.servizio=servizio;
}
public synchronized void sospendi(){
sospeso=true;
}
public synchronized void risveglia(){
sospeso=false;
notify();
}
public void chiudi(){
avviato=false;
risveglia();
}
public void run(){
servizio.inizializza(); //Codice eseguito solo all'avvio del servizio
while(avviato){
synchronized(this){
if(sospeso){
try{
wait();
}
catch(InterruptedException e){
System.out.println(e);
}
}
}
servizio.esegui(); //E' il compito del servizio
}
servizio.chiudi();
}
}
semplifichi il codice, rendi il sorgente più chiuso alle modifiche ed eviti un'inutile gerarchia di classi :)
ciao
Ti ringrazio per la dritta, ma una volta per tutte non è che midici come cavolo cambio per non avere quell'errore di cui avete discusso...
Comunque ho scritto quel codice pensando che poi la classe ThreadDiServizio l'avrei usata solo come inner class.
Infatti mi sono creato poi un'altra classe la quale crea una classe ThreadDiServizio come inner class riscrivendo i metodi astratti.
String s="Thread 1";
ThreadDiServizio ts=new ThreadDiServizio(s){
public void inizializza(){
---codice---
}
public void esegui(){
---codice---
}
public void chiusura(){
chiudiConnessione();
---codice---
}
};
In particolare poi io mi sono creato una classe Servizio, la quale possiede una inner class di ThreadDiServizio, e anch'essa la uso istanziandola come inner class...così:
Servizio.java
public class Servizio extends Protocollo{
public Servizio(String s){
ThreadDiServizio ts=new ThreadDiServizio(s){
public void inizializza(){
avvio();
}
public void esegui(){
compito();
}
public void chiusura(){
chiudiConnessione();
esci();
}
};
}
public void compito(){
}
public void avvio(){
}
public void esci(){
}
public void sospendiServizio(){
ts.sospendi();
}
public void riavviaServizio(){
ts.risveglia();
}
public void arrestaServizio(){
ts.chiudi();
}
}
Secondo te è un brutto modo di programmare?
Ovviamente poi per usare la casse Servizio la istanzio come inner class e ne riscrivo i metodi avvio(), compito() ed esci().
A me sembrava abbastanza comodo così, ma probabilemente è un casino assurdo, giusto?
guarda ad okkio sembrerebbe corretto per la variabile sospeso, ma lo stesso problema che prima era sulla variabile sospeso adesso lo ritrovi sulla variabile avviato :)
Tra l'altro nella classe che hai scritto noto un piccolo problema di design. Hai reso ThreadDiServizio una classe astratta con 3 metodi astratti. Guardando questi tre metodi nn si può fare a meno di notare alcune cose:
1) Con questi metodi darai ad ogni sottoclasse di ThreadDiServizio 2 responsabilità (gestione del servizio e del loop di esecuzione) il che viola il principio di singola responsabilità
2) Ogni volta che dovrai implementare una nuovo servizio dovrai ereditare da ThreadDiServizio con nuovi metodi esegui, inizializza e chiudi
ti viene in aiuto il pattern command (opportunamente adattato alle tue esigenze):
interface Servizio{
public void inizializza();
public void esegui();
public void chiudi();
}
public class ThreadDiServizio extends Thread{
private boolean sospeso=true,avviato=true;
private Servizio servizio;
public ThreadDiServizio(String s,Servizio servizio){
super(s);
this.servizio=servizio;
}
public synchronized void sospendi(){
sospeso=true;
}
public synchronized void risveglia(){
sospeso=false;
notify();
}
public void chiudi(){
avviato=false;
risveglia();
}
public void run(){
servizio.inizializza(); //Codice eseguito solo all'avvio del servizio
while(avviato){
synchronized(this){
if(sospeso){
try{
wait();
}
catch(InterruptedException e){
System.out.println(e);
}
}
}
servizio.esegui(); //E' il compito del servizio
}
servizio.chiudi();
}
}
semplifichi il codice, rendi il sorgente più chiuso alle modifiche ed eviti un'inutile gerarchia di classi :)
ciao
Ma poi quando devo creare istanziare un oggetto della classe ThreadDiServizio come faccio in questo caso?
Passi al costruttore un oggetto della classe Servizio che è una interfaccia, quindi immagino che prima mi devo creare una classe che implementi Servizio dove riscrivi i metodi dell'interfaccia e poi passarla a ThreadDiServizio giusto?
Si può fare tutto in una unica classe vero? poi passo this al costruttore di ThreadDiServizio, correggimi se sbaglio.
Qui http://www-sop.inria.fr/lemme/Laurent.Thery/lsp/pattern.html ho trovato una lista dei vari pattern che si posso utilizzare, azz non credevo ci fossero così tante cosine interessanti, comunque in particolare è spiagato il pattern command da te citato:
Command
Il pattern command permette di astrarre la chiamata di un metodo.
In Java, un command prende la forma di un'intefaccia:
interface Command {
void execute();
}
Adesso data la class A
class A {
...
public void doIt() {
...
}
...
}
per trasformare la chiamata del metodo doIt in un command, si fa:
class ACommand implements Command {
A a;
ACommand(A a) {
this.a = a;
}
public void execute() {
a.doIt();
}
}
Adesso nella class B si può permettere di eseguire il metodo doIt senza conoscere A:
class B {
Command c;
void setCommand(Command c) {
this.c = c;
}
void run() {
c.execute();
}
}
Quello che non ho capito è la classe B che in pratica serve per usare la classe A, non capisco come posso utilizzare l'interfaccia Command e creare un oggetto c, non dovrebbe utilizzare ACommand?
The3DProgrammer
31-07-2006, 10:02
Qui http://www-sop.inria.fr/lemme/Laurent.Thery/lsp/pattern.html ho trovato una lista dei vari pattern che si posso utilizzare, azz non credevo ci fossero così tante cosine interessanti, comunque in particolare è spiagato il pattern command da te citato:
Command
Il pattern command permette di astrarre la chiamata di un metodo.
In Java, un command prende la forma di un'intefaccia:
interface Command {
void execute();
}
Adesso data la class A
class A {
...
public void doIt() {
...
}
...
}
per trasformare la chiamata del metodo doIt in un command, si fa:
class ACommand implements Command {
A a;
ACommand(A a) {
this.a = a;
}
public void execute() {
a.doIt();
}
}
Adesso nella class B si può permettere di eseguire il metodo doIt senza conoscere A:
class B {
Command c;
void setCommand(Command c) {
this.c = c;
}
void run() {
c.execute();
}
}
Quello che non ho capito è la classe B che in pratica serve per usare la classe A, non capisco come posso utilizzare l'interfaccia Command e creare un oggetto c, non dovrebbe utilizzare ACommand?
è proprio questo il trucco :)
usando un'interfaccia, impedisci a B di conoscere i dettagli relativi a ciò che gli eventuali comandi dovranno fare. In questo modo ogni volta che dovrai riscrivere e/o modificare un comando potrai andare ad estendere l'interfaccia command, senza andare a toccare l'implementazione di B.
esempio:
interface Command{
public void execute();
}
class Command1 implements Command{
public void execute(){ ..... }
}
class Command2 implements Command{
public void execute(){ ..... }
}
...
public static void main(String args[]){
B executor=new B();
b.setCommand(new Command1());
b.execute(); //B esegue command1
b.setCommand(new Command2());
b.execute(); //B esegue command2
etc etc..
}
ovviamente nel codice di prima (quello di ThreadDiServizio) puoi evitare di passare il servizio nel costruttore e mettere un metodo setServizio(Servizio serv), oppure entrambe le scelte. Per il problema su avviato ci sto pensando, non conviene mettere tutto il while in un blocco synchronized xkè altrimenti impedisci agli altri thread concorrenti di accedere alla variabile avviato anche mentre è in esecuzione esegui()... Ora trovo una soluzione e te la posto;)
ciao
Ti ringrazio sei stato chiarissimo!
Comunque la storia sui pattern mi ha incuriosito, siccome sono tanti magari ci apro un thread apposta.
Grazie ancora intanto.
Riguardo a volatile avete ragione... il caldo mi ha fuso il cervello. :doh:
Ho visto "new Thread..." e sono andato in confusione :muro:
Comunque domani vado a raffreddarmi il cervello :D
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.