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
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
Creare un metodo callback nel thread che deve aspettare l'esecuzione?
--
sv.
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
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.
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
Concurrent Programming in Java: Design Principles and Patterns di Doug Lea
> 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.