Newsgroup: it.comp.java
Titolo: Attendere la fine di un thread

Ragazzi,
mi sono incastrato in un problema sulla sincronizzazione dei thread.
Il mio obiettivo è attendere che un tread termini prima di continuare
con l'esecuzione di un metodo.
Di seguito vi descrivo a grandi linee come è strutturata
l'applicazione. Si tratta di un meccanismo per l'accesso ai dati.
Sostanzialmente una classe richiedente (A) invoca un metodo (execute
()) di un Singleton che estende Thread (da qui in poi DE) che, nel suo
metodo run(), è in costante attesa di nuove richieste. Una volta
ricevuta una nuova richeista (tramite l'invocazione del metodo sopra
citato), DE crea un nuovo processo (da qui DEP) che elabora la
richeista fatta da A.
Tanto per essere più chiaro di seguito riporto un estratto del metodo
execute() di DE
----------------------------------------------------------------
    public synchronized String execute() {
        DER req = new DER(context, qname, qparams);
        requests.add(req);
        this.notify();
        DQ q = null;
        //[!]: qui occorre ua sincronizzazione su DEP
        DEP depThread = req.getDEP(); //recupera il processo che
gestisce la richeista [!]: ritorna null in quanto non sincronizzato
con run()
            try {
                depThread.join();  //attendi che il thread muoia [!]:
qui viene sollevata una NullPointerException
            } catch (InterruptedException eDep) {  //quando il thread
muore recupera i dati dell'esecuzione
                q = depThread.getExecutionResult();
            }
        return (q == null) ? null : q.toString();
    }
----------------------------------------------------------------
e un estratto del metodo run() di DE
        try {
            while (true) { //tieni attivo il processo
                if (requests.isEmpty() || runningThread == maxThread)
                    try {  //se non ci sono richieste pending oppure
se tutti i processi sono occupati
                        wait();  //sospendi il processo
                    } catch (InterruptedException e) {
                        //è arrivata nuova richiesta oppure si è
liberato quelhce processo
                    }
                //se il processo è attivo...
                try {
                    //avvia un processo per la gestione della
richiesta
                    DER der = requests.firstElement();
                    DEP dep = new DEP(der);
                    der.setDataEngineProcessor(dep);
                    dep.start();
                } catch (Exception e) {
                    //Errore nell'istanziazione del processo per
l'elaborazione della richiesta
                } finally {
                    //elimina la richiesta elaborata
                    requests.removeElementAt(0);
                }
            }
        } finally {
            ///esecuzone del processo principale terminata
        }
    }
----------------------------------------------------------------
Il mio obiettivo è di sincronizzare il metodo execute() sull'oggetto
"der" in modo tale da recuperare il valore del processo DEP sse questo
è disponibile (cioè quando è stato settato da
"der.setDataEngineProcessor(dep);" nel metodo run() di DE).
Ho provato con i vari wait(), notify(), notifyall(), join(), e con i
blocchi/metodi "syncrhronized" ma se non surgelo tutta l'applicazione
ottengo una fastidiosa IllegalMonitorStateException.
Potreste gentilemnte darmi qualche dritta su come risolvere la
questione?
Grazie mille a tutti

Ciao Sergio...
Allora, IllegalMonitorStateException la ottieni quando cerci di invocare una
wait o una notify o qualsiasi altro metodo relativo alla sincronizzazione
senza aver acquisito il lock...
Se ho capito bene quello che devi fare, credo potresti risolvere il tutto
utilizzando due semafori evento!
Inizializzi un semaforo a zero
Semaphore s = new Semaphore(0);
....
execute(){
    .....
    ....
    s.acquire();
   /*
        il processo che acquisisce il semaforo senza posti disponibili viene 
messo in coda... Questo viene risvegliato non appena si libera una 
posizione...
    questa posizione viene aggiunta mediante la chiamata della release sul 
semaforo che avviene nel run...
    � semplice sincronizzazione di processi mediante semafori... protesti 
anche farlo mediante l'utilizzo di Condition...
    (secondo me molto pi� indicate)..
*/
}
run(){
    ...
    ...
    ...
    s.release();
}
Spero di esserti stato utile...
TempestaT400
 

 Grazie mille a tutti
Creare un metodo callback nel thread che deve aspettare l'esecuzione?
--
sv.

 - Mostra testo citato -
Callback nel senso di implementare una sorta di observer? Ci avevo
pensato solo che questo pattern in genere l'ho usato in situazioni
asincrone, quello che mi manca qui è invece proprio la
sincronizzazione tra i metodi.... ovviamente correggimi se ho detto
qualche stupidaggine :)
Ho provato la soluzione proposta da TempestaT400 e sembra che il
problema sia stato agevolmente risolto :). In ogni caso mi piacerebbe
avere anche qualche dettaglio in più riguardo la tua idea (magari
potrebbe tornare utile in futuro a me o a qualcun'altro lettore del
ng...). Potresti gentilmente indicare qualche altro dettaglio in
merito?
Grazie 1000 a tutti. Siete come sempre fondamentali ;)
Ciao
Sergio

 Sergio
Se ho capito la tua situazione hai un thread che svolge un lavoro ed un 
altro che invia i job da fare e deve attendere il risultato.
Quindi il thread che svolge la computazione potrebbe mettere il lavoro 
eseguito in una coda (bloccante) mentre chi ha sottomesso il lavoro la 
legge.
Il problema ti si generava perch� il metodo req.getDEP() non era 
bloccante (cosa che in alcuni casi � utile), ussanto il callback, quando 
il thread che svolge il lavoro ha terminato invoca sull'oggetto il 
metodo callback (es. setWorkDone(Work w) ) che potrebbe banalmente 
inserirlo in una coda.
Eventualmente prova a guardare java.util.concurrent.Future ed il Worker 
Thread pattern.
--
sv.

 - Mostra testo citato -
Grazie dei chiarimenti. Andrò subito a guardarmi i riferimenti che mi
hai indicato.
La questione dei thread e della concorrenza è una cosa che mi
interessa molto e che vorrei approfondire per riuscire a muovermi
agevolmente in questo ambito.
Un'altra domanda, immagino banale ma che contribuisce a chiarirmi
meglio i dubbi sulla sincronizzazione: supponaimo che che DE è un
singleton e che execute sia un metodo non-statico della classe,
supponiamo inoltre che il metodo req.getDEP() sia bloccante. Ciò
comporta che si bloccherebbe tutta l'esecuzione del metodo execute()
di DE giusto? cioè DE non sarebbe più in grado di accettare chiamate
al metodo execute() fino a che l'esecuzione non viene "sbloccata" dal
dal ritorno di req.getDEP() e, in questo modo, andrei a perdere il
parallelismo che cercavo...
Scusa l'eventuale stupidaggine che ho scritto ;)
Ciao
Sergio

 
si esatto, ci� deriva dal fatto che hai due metodi bloccanti innestati, 
quindi req.getDEP(), quando metterebbe in wait il thread, ne potrebbe 
accettare altri, ma execute() rimarrebbe comunque bloccata.
Il fatto � che per come hai strutturato l'applicazione, execute non 
permette il parallelismo, visto che dovrebbe attendere la fine di un thread.
Mi permetto una piccola nota, credo che Semaphore sia da mettere a 1 e 
non a 0, altrimenti il primo come fa ad entrare?
--
sv.