View Full Version : "eventi" (di sincronizzazione) in Java
in un programma Java ho un certo numero di threads che devono bloccarsi in attesa che si verifichi un certo evento; questo evento dovrebbe essere provocato da un altro thread che subito dopo dovrebbe risvegliare tutti gli altri.
in altre parole dovrei realizzare in Java un meccanismo come gli eventi di Win32.
stavo pensando di utilizzare come oggetto che rappresenta l'evento (stavolta inteso come meccanismo di sincronizzazione) un generico Object: i thread si bloccano con la wait e il thread che provoca l'evento li sblocca con notifyAll. è una cavolata o ha senso?
un po' di pseudocodice:
private Object event;
.
.
.
<metodo chiamato dal thread che attende>
while (!<condizione che termina definitivamente l'attesa>) {
try {
event.wait();
}
catch (InterruptedException e) {
}
}
.
.
.
<metodo chiamato dal thread che provoca l'evento>
event.notifyAll();
aggiungo che tutto il meccanismo deve verificarsi più volte. vi pare corretto? devo forse richiamare un'altra volta notify o notifyAll subito dopo che il thread che attende è uscito dalla wait?
Ciao, tempo fa aprii un thread simile, guarda se ti può tornare utile
http://www.hwupgrade.it/forum/showthread.php?t=1249755
^TiGeRShArK^
12-12-2006, 15:47
mmmm..
al java day di due sabati fa hanno postato un interessante esempiuccio ke utilizzava le variabili di tipo volatile per mantenere la coerenza tra + thread...
spè ke ti trovo il codice :p
class MyThread extends Thread {
public void run() {
while (!done) { // fai qualcosa ... }
}
public void setDone() { done = true; }
private volatile boolean done;
}
prova così :D
^TiGeRShArK^
12-12-2006, 15:49
dimenticavo..
le volatile non garantiscono l'atomicità...
Per l'atomicità dovresti usare il tipo java.util.concurrency.Atomic o qualcosa del genere :p
è, ho capito ma sti thread non devono mica spremere la CPU, si devono bloccare :D
MEMon, ho leggiucchiato il thread che mi hai linkato ma non riesco a capacitarmi: possibile che una cosa simile si debba implementare per forza con tutto quel codice? O_O
io volevo una cosa semplice semplice, non ditemi che devo scrivermi la mia classe Event :cry:
il mio codice funzica? ovviamente no, visto che non ho capito un cacchio dei monitor; perché non funzica? :help: fatemi capire :D
^TiGeRShArK^
12-12-2006, 16:22
è, ho capito ma sti thread non devono mica spremere la CPU, si devono bloccare :D
MEMon, ho leggiucchiato il thread che mi hai linkato ma non riesco a capacitarmi: possibile che una cosa simile si debba implementare per forza con tutto quel codice? O_O
io volevo una cosa semplice semplice, non ditemi che devo scrivermi la mia classe Event :cry:
il mio codice funzica? ovviamente no, visto che non ho capito un cacchio dei monitor; perché non funzica? :help: fatemi capire :D
non funziona xkè ti lancerebe l'eccezione ke stai sbloccando un monitor da un oggetto ke non è l'owner del monitor..
e c'ha anke ragione direi :D
Lo pseudo codice di 71104 non fa una piega. Probabilmente si tratta solo di un dettaglio mancante. Non ricordo il contesto del thread segnalato da Memon ma non è necessario ingrufolarsi in milione di linee per tradurre quello pseudocodice in Java.
Noterei come ci sia una corrispondenza praticamente diretta tra le intenzioni espresse e la forma in cui sono traducibili.
import java.util.concurrent.*;
import java.util.concurrent.locks.*;
import java.util.*;
public class Main {
private final Lock signalLock = new ReentrantLock();
private final Condition signalCondition = signalLock.newCondition();
public void waitForSignal() {
try {
signalLock.lock();
signalCondition.await();
} catch(InterruptedException ex) {
} finally {
signalLock.unlock();
}
}
public void signal() {
try {
signalLock.lock();
signalCondition.signalAll();
} finally {
signalLock.unlock();
}
}
public static void main(String[] args) {
final Main main = new Main();
Runnable stuntTask = new Runnable() {
public void run() {
main.waitForSignal(); //qui i thread si spantegano sulla barriera
System.out.println(Thread.currentThread().getName() + " free!!!!");
}
};
for(int i = 0; i < 10; i++) {
new Thread(stuntTask, "StuntThread n. " + i).start();
}
System.out.println("Press enter to release stuntthreads...");
Scanner in = new Scanner(System.in);
in.nextLine();
main.signal(); //e qui vengono aperte le porte
}
}
La parte non evidenziata è "tanto per prova'".
^TiGeRShArK^
12-12-2006, 16:40
eh bhè..
questo mi sa ke funziona..
ma non stai usando wait e notifyAll stai usando i costrutti di java 5 :D
il codice scritto da 71104 avrebbe lanciato un'eccezione xkè ank'io l'ho scritto un migliaio di volte masokisticamente senza imparare mai :asd:
il wait e notifyAll danno quel problema perchè un monitor bloccato su un oggetto può essere sbloccato solo dall'owner del monitor (ke mi sa ke è l'oggetto stesso se non erro).
Cmq non lo so spiegare bene dato ke ho le idee un pò confuse anch'io su wait e notify.
Molto ma molto meglio utilizzare i costrutti ad alto livello forniti da java.util.concurrent :D
volatile dalla 1.5 in funziona "in tutto e per tutto".
volatile String pippo = "p";
public void asd()
{
a();
String c = pippo+"a";
b();
}
dalla 1.5 in poi è garantito che String c = pippo+"a"; viene eseguita dopo a(); e prima di b();
prima della 1.5 invece c'erano dei buchi...(letto tutto su un jsr)
^TiGeRShArK^
12-12-2006, 16:51
volatile dalla 1.5 in funziona "in tutto e per tutto".
volatile String pippo = "p";
public void asd()
{
a();
String c = pippo+"a";
b();
}
dalla 1.5 in poi è garantito che String c = pippo+"a"; viene eseguita dopo a(); e prima di b();
prima della 1.5 invece c'erano dei buchi...(letto tutto su un jsr)
+ ke altro non era garantito il funzionamento in tutte le implementazioni delle virtual machine.
Questo perchè le specifiche del memory model di java erano troppo lacunose e davano adito a diverse interpretazioni, e soprattutto alcuni costrutti utilizzati per migliorare le performance della gestione dei thread dovevano x forza di cose "violare" le specifiche (se si può dire violare x una specifica non ben definita)
Invece dalla versione 5 in poi è stata definita correttamente la relazione di Happens Before x il memory model e sono state aggiornate le specifiche in maniera congruente, cosikkè tutte le impliementazioni ke seguono le specifiche di java 5 non danno + alcun problema con il multi-threading (non che prima ne dessero x forza...ma diciamo che andava un pò a culo a seconda dell'implementazione :D)
L'intuizione di Tigershark è corretta.
Il linguaggio stabilisce che l'invocazione di wait e notify deve avvenire in condizione di possesso esclusivo, parte del Thread che esegue l'invocazione, del monitor associato all'istanza che possiede i metodi wait o notify invocati.
In Java tale possesso esclusivo è garantito nel caso in cui l'accesso avvenga all'interno di un blocco sincronizzato sull'oggetto a cui appartiene il metodo wait/notify invocato o all'interno di un metodo sinchronized nel caso in cui l'oggetto in questione sia "this".
Cioè sincronizzi, sull'oggetto X, per escludere che qualche altro Thread possa mettere le mani sul monitor associato a X, mentre invochi wait o notify su X.
Non fatico ad immaginare che dietro tale regola vi sia qualche necessità strutturale. Ma per quello che interessa a noi basta e avanza che sia la lingua ad imporlo.
[AGGIUNTO]
P.s.: mi riferivo al wait e al notify, non al volatile.
L'intuizione di Tigershark è corretta. infatti l'eccezione me la lancia, a essere errato il mio codice era errato :D
dunque per capirci :wtf:
se io volessi realizzare una mia classe Event in questa forma:
class Event
{
public void myWait() // può essere chiamato da qualsiasi thread in qualsiasi momento
{
...
}
public void myNotifyAll() // idem come sopra
{
...
}
}
come dovrei implementare i metodi myWait e myNotifyAll nella maniera più semplice possibile? :cry:
vanno bene i metodi waitForSignal e signal dell'esempio di PGI-Bis? cioè devo usare come minimo due oggetti (un ReentrantLock e una Condition)?
a me pare assurdo che una perla come Java abbia una tale carenza :mbe:
in Win32 è sufficiente aprire un solo HANDLE e si ha un meccanismo notevolmente versatile :huh:
mah
a proposito, non è che tante volte in Java 6 c'è una bella classe EventEspeciallyMadeFor71104 già pronta? :help:
no perché io ho già 2 buoni motivi per passare a Java 6 (di cui uno addirittura ottimo), e questo non sarebbe altro che il terzo :D
ah, dimenticavo: sempre facendo riferimento al confronto con Win32, l'esempio di PGI-Bis NON è "manual reset", giusto? :help:
^TiGeRShArK^
12-12-2006, 20:17
infatti l'eccezione me la lancia, a essere errato il mio codice era errato :D
dunque per capirci :wtf:
se io volessi realizzare una mia classe Event in questa forma:
class Event
{
public void myWait() // può essere chiamato da qualsiasi thread in qualsiasi momento
{
...
}
public void myNotifyAll() // idem come sopra
{
...
}
}
come dovrei implementare i metodi myWait e myNotifyAll nella maniera più semplice possibile? :cry:
vanno bene i metodi waitForSignal e signal dell'esempio di PGI-Bis? cioè devo usare come minimo due oggetti (un ReentrantLock e una Condition)?
a me pare assurdo che una perla come Java abbia una tale carenza :mbe:
in Win32 è sufficiente aprire un solo HANDLE e si ha un meccanismo notevolmente versatile :huh:
mah
ma perchè il mio scheletro di codicillo non ti piaceva? :D
guarda se scritto ks ti piace di + ;)
public class ProvaThread {
volatile boolean condition = false;
public ProvaThread() {
while(condition) {
//do something;
}
}
public void myNotify() {
condition = true;
}
public void myWait() {
condition=false;
}
}
Se non ho invertito il significato di wait e notify dovrebbe andare :p
^TiGeRShArK^
12-12-2006, 20:19
mmmmm..
ora ho capito ke intendevi :asd:
e mi sa ke il mio codice non va bene xkè comunque aspetta di finire quello ke sta facendo nel ciclo e non si ferma immediatamente :p
boh..
dai un okkiata a java.util.concurrent e vedi se c'è qualco'altro ke fa al caso tuo :D
ma perchè il mio scheletro di codicillo non ti piaceva? :D è che non va bene perché il while succhia CPU; io volevo bloccarmi nell'attesa...
^TiGeRShArK^
12-12-2006, 20:36
è che non va bene perché il while succhia CPU; io volevo bloccarmi nell'attesa...
ahhh..
e bhè?
ke problema c'è? :D
diamonds non ti ha insegnato niente? ;)
un bel Thread.sleep(1) dentro il while e il problema è risolto..
e se vedi ke succhia ancora cpu mettigli 2, 3 o quello ke ti pare :D
che ne diti della comoda CyclicBarrier (http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/CyclicBarrier.html)
presente in java 5.0
infatti l'eccezione me la lancia, a essere errato il mio codice era errato :D
dunque per capirci :wtf:
se io volessi realizzare una mia classe Event in questa forma [OMISSIS]
come dovrei implementare i metodi myWait e myNotifyAll nella maniera più semplice possibile
Sarebbe:
public class Event {
private boolean wakeup;
public synchronized void myWait() {
try {
while(!wakeup) {
wait();
}
} catch(InterruptedException ex) {
return;
}
}
public synchronized void myNotifyAll() {
wakeup = true;
notifyAll();
}
}
Per usare una barriera deve avere una soglia, cioè deve conoscere in anticipo il numero di Thread che devono raggiungere la barriera prima che questa liberi i Thread.
Sarebbe:
public class Event {
private boolean wakeup;
public synchronized void myWait() {
try {
while(!wakeup) {
wait();
}
} catch(InterruptedException ex) {
return;
}
}
public synchronized void myNotifyAll() {
wakeup = true;
notifyAll();
}
} òòòòòòòòò grazie! :D
stavo per rispondere: "è, ma così mi si lamenta che non ho il monitor", ma arrivato a pensare la M di monitor mi sono corretto dicendomi "i metodi sono synchronized :read:"
+ ke altro non era garantito il funzionamento in tutte le implementazioni delle virtual machine.
Questo perchè le specifiche del memory model di java erano troppo lacunose e davano adito a diverse interpretazioni, e soprattutto alcuni costrutti utilizzati per migliorare le performance della gestione dei thread dovevano x forza di cose "violare" le specifiche (se si può dire violare x una specifica non ben definita)
Invece dalla versione 5 in poi è stata definita correttamente la relazione di Happens Before x il memory model e sono state aggiornate le specifiche in maniera congruente, cosikkè tutte le impliementazioni ke seguono le specifiche di java 5 non danno + alcun problema con il multi-threading (non che prima ne dessero x forza...ma diciamo che andava un pò a culo a seconda dell'implementazione :D)
avevo letto anchio tutta quella pappardella di roba, ma era anti-pigro ricordarla tutta o andarsela a ritrovare :asd:
cmq se a qualcuno interessa...
parte 1
http://www-128.ibm.com/developerworks/library/j-jtp02244.html
parte 2
http://www-128.ibm.com/developerworks/java/library/j-jtp03304/
i cambiamenti al memory model da 1.4->1.5 :)
per la serie quando le stringhe erano modificabili :asd:
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.