PDA

View Full Version : [Java] synchronization


mad_hhatter
29-08-2007, 14:49
perché questo codice

class Prova {
public static Object obj = new Object();
public static String s = "0";

public static void main(String[] args) {
// creo 2 thread che eseguano il run di Incrementor
// aspetto che i 2 thread terminino
// stampo il valore di s
}
}

class Incrementor implements Runnable {

public void run() {
for (i = 0; i < 1000000; i++) {
synchronized(Prova.s) {
s = "" + (Integer.parseInt(Prova.s) + 1);
}
}
}

}

porta a un valore finale di s errato mentre se mi sincronizzo su Prova.obj invece che su Prova.s funziona correttamente?

andbin
29-08-2007, 15:30
porta a un valore finale di s errato mentre se mi sincronizzo su Prova.obj invece che su Prova.s funziona correttamente?I due thread devono chiaramente sincronizzarsi sullo stesso oggetto (altrimenti la sincronizzazione non avrebbe effetto). Sincronizzarsi su un oggetto referenziato da una variabile static va appunto bene.
Ma il fatto è che mentre il reference obj è e rimane fisso, il reference alla stringa cambia per via della concatenazione! Per tale motivo non va bene.

mad_hhatter
29-08-2007, 15:35
mille grazie!

nuovoUtente86
30-08-2007, 16:48
synchronized(Prova.s) {
s = "" + (Integer.parseInt(Prova.s) + 1);
}


è la priva volta che vedo questo tipo di codice,ma cosa fa esattamente?

andbin
30-08-2007, 16:58
synchronized(Prova.s) {
s = "" + (Integer.parseInt(Prova.s) + 1);
}


è la priva volta che vedo questo tipo di codice,ma cosa fa esattamente?synchronized è la parola chiave che permette di gestire una "mutua esclusione" tra più thread. Ogni oggetto ha un monitor, di cui un thread può fare il lock e unlock. Solo un thread per volta può acquisire il lock sul monitor. Gli altri eventuali thread che cercano di acquisire il lock su un monitor già lockato, sono bloccati fino a quando viene fatto l'unlock sul monitor.

PGI-Bis
30-08-2007, 17:02
la parola chiave "synchronized" stabilisce che il metodo o, nel caso in questione, il blocco di codice è ad accesso mutualmente esclusivo.

Gli esclusi sono i Thread: solo un Thread alla volta può trovarsi all'interno di quel blocco (ad eseguirne il contenuto).

La mutualità è prodotta attraverso un monitor, cioè un valore di controllo che dice "in questo istante sono posseduto da qualcuno". Stile esorcista.

Ai fini della sincronizzazione, ogni Object Java è un monitor. Cioè tutto tranne i primitivi.

Bene, quella forma:

synchronized(qualcosa) {

}

Dice che il blocco di codice marcato "synchronized" è ad accesso mutualmente esclusivo e l'esclusione è stabilita usando come monitor "qualcosa". Significa quindi che se un altro Thread detiene il monitor "qualcosa" nessun'altro Thread potrà entrare nel blocco sincronizzato finchè quel Thread non abbia rilasciato il monitor.

Il monitor viene rilasciato automaticamente all'uscita, comunque motivata, dal blocco sincronizzato.

La forma:

synchronized {

}

è un'abbreviazione per:

synchronized(this) {

}

La forma:

synchronized void unMetodo() {
...contenuto del metodo
}

Equivale a:

void unMetodo() {
synchronized {
...contenuto del metodo
}
}

Nel caso del codice incollato, il monitor è il campo statico s di Prova che vale, a scelta dell'implementazione, null o "s". Idem per obj, che potrebbe valere null o un oggetto.

nuovoUtente86
30-08-2007, 17:03
synchronized è la parola chiave che permette di gestire una "mutua esclusione" tra più thread. Ogni oggetto ha un monitor, di cui un thread può fare il lock e unlock. Solo un thread per volta può acquisire il lock sul monitor. Gli altri eventuali thread che cercano di acquisire il lock su un monitor già lockato, sono bloccati fino a quando viene fatto l'unlock sul monitor.

si ma io l' ho sempre usata sui metodi ma non avevo mai visto questo tipo di utilizzo su una variabile statica.

Poi si discuteva sulla stringa:è ver che con la concatenazione in realtà si passa a referenziare un nuovo oggetto ma non capisco come mai fallisca il metodo.

s all' inizio punterà a "ciao" poi se si concatena punterà ad un nuovo oggetto " ciao ciao" ma perchè si ha il problema sulla sincronizzazione?

PGI-Bis
30-08-2007, 17:03
E be', e dammi una mano andbin! Se mi scrivi quattro righe è chiaro che duplico le risposte! E prenditi un po' di tempo! :D

71104
30-08-2007, 18:01
Ogni oggetto ha un monitor, di cui un thread può fare il lock e unlock. il lock su cui gli statement synchronized si sincronizzano credo non c'entri nulla col monitor di un oggetto, che sarebbe invece quello su cui si sincronizzano i metodi wait, notify, notifyAll... sono due meccanismi indipendenti.

PGI-Bis
30-08-2007, 18:08
No, è lo stesso monitor.

71104
30-08-2007, 18:12
No, è lo stesso monitor. scusa ma allora bisogna necessariamente usare synchronized prima di chiamare Object.wait ?

71104
30-08-2007, 18:14
scusa ma allora bisogna necessariamente usare synchronized prima di chiamare Object.wait ? come non detto... adesso ho capito come funziona :mbe:

a questa domanda tu avresti risposto di si, e io subito dopo avrei chiesto: "ma allora a che serve notifyAll dato che un solo thread alla volta può chiamare wait?", ma ho letto ora che wait rilascia il monitor ^^

mad_hhatter
30-08-2007, 18:15
[edit] ti sei già risposto

nuovoUtente86
30-08-2007, 18:16
bisogna chiamare syncronized prima di wait?

PGI-Bis
30-08-2007, 18:22
Bisogna invocare wait() all'interno di un blocco sincronizzato sull'oggetto che subisce l'invocazione di wait().

Cioè se:

x.wait();

allora dev'essere:

synchronized(x) {
x.wait();
}

Se l'oggetto è "this" allora si può usare la forma breve:

synchronized {
wait();
}

Ps: ho omesso la gestione delle eccezioni.

pisto
30-08-2007, 19:00
c'è un modo non bloccante per vedere se il monitor di un certo oggetto è già sotto il controllo di un Thread?

PGI-Bis
30-08-2007, 19:12
C'è il metodo holdsLock di Thread che però non dice se sia o non sia bloccante, cioè se il controllo sia fatto tentando un'acquisizione del monitor.

andbin
30-08-2007, 20:46
si ma io l' ho sempre usata sui metodi ma non avevo mai visto questo tipo di utilizzo su una variabile statica.

Poi si discuteva sulla stringa:è ver che con la concatenazione in realtà si passa a referenziare un nuovo oggetto ma non capisco come mai fallisca il metodo.

s all' inizio punterà a "ciao" poi se si concatena punterà ad un nuovo oggetto " ciao ciao" ma perchè si ha il problema sulla sincronizzazione?È un problema di grana molto "fine" ma esiste.

All'inizio si ha un oggetto "0". I thread <A> e <B> cercano di ottenere il lock su "0". <A> ad esempio ci riesce ed esegue il blocco, mentre <B> rimane bloccato sempre su "0". <A> crea un nuovo oggetto "1" e cambia il reference. <B> rimane ancora bloccato su "0" (che esiste ancora ... non è sparito). <A> rilascia il lock su "0" e quindi <B> può ottenere il lock su "0" (che era in attesa). Ma intanto 's' è cambiato quindi <A> cerca di fare il lock su "1" e non più "0".
Alla fine della storia che succede? Che ci può essere un istante in cui entrambi i thread entrano nel blocco perché hanno il lock su oggetti diversi. E questo è moooolto pericoloso! ;)


E be', e dammi una mano andbin! Se mi scrivi quattro righe è chiaro che duplico le risposte! E prenditi un po' di tempo! :DSai ... dovremmo metterci d'accordo noi due quando si tratta di rispondere su Java ;) .... che so, fare una risposta cooperativa by andbin & PGI-Bis. :D

Se l'oggetto è "this" allora si può usare la forma breve:

synchronized {
wait();
}Ehm .. non c'è la forma breve. La parte (Espressione) ci deve sempre essere.

PGI-Bis
30-08-2007, 21:02
Sì, pardon, intendevo la forma:

synchronized void blabla() {

}

anzichè:

void blabla {
synchronized(blu) {

}
}

andremosfet
03-12-2007, 16:04
scusate ragazzi una domandina..se invoco il metodo wait() lo devo sempre includere in un blocco synchronized??(ovviamente oltre a gestire l'eccezione)

andbin
03-12-2007, 16:12
scusate ragazzi una domandina..se invoco il metodo wait() lo devo sempre includere in un blocco synchronized??(ovviamente oltre a gestire l'eccezione)La regola, in generale, è che il wait() lo devi invocare su un oggetto di cui hai acquisito il lock.
Poi come e dove hai acquisito il lock non ha importanza per il wait.
La stessa regola vale per notify()/notifyAll().

andremosfet
03-12-2007, 16:31
ok grazie...