La notify e notifyAll per risvegliare un thread funziona solo in un metodo synchronized?? non si può adottare in un metodo che non lo è? grazie
La notify e notifyAll per risvegliare un thread funziona solo in un metodo synchronized?? non si può adottare in un metodo che non lo è? grazie
confondi i concetti: synchronized ti protegge da eventuali accessi contemporanei da parte di due thread differenti.
notify viene utilizzato per indicare ad un thread in attesa di un evento che deve risvegliarsi, ma non è detto che il thread che è in attesa si trovi in un blocco sync!!
RTFM Read That F*** Manual!!!
Si può adottare, nel senso che nessuno ti vieta di farlo, ma che senso avrebbe? Se un metodo (o porzione di codice) non è sincronizzato, nessun thread si bloccherà nell'eseguirlo contemporaneamente ad un altro... quindi a che serve notificare un "risveglio" quando (potenzialmente) nessun thread è bloccato?
A meno che tu non voglia risvegliare qualcun altro, bloccato da qualche altra parte...
Ciao.![]()
"Perchè spendere anche solo 5 dollari per un S.O., quando posso averne uno gratis e spendere quei 5 dollari per 5 bottiglie di birra?" [Jon "maddog" Hall]
Fatti non foste a viver come bruti, ma per seguir virtute e canoscenza
Ma potete spiegarmi perchè poi non si risvegliano con la notifyAll.
Io avvio i client (il primo è giocatore BIANCO e fa il wait, poi il GIALLO e fa wait() e infine il NERO che dovrebbe riavegliarli ma non lo fa).
Cosa sbaglio??
Questo è il codice del ServerThread:
codice:public synchronized void controlloInizio() throws InterruptedException, IOException{ if(giocatore.equals(Giocatore.NERO)){ partitaIniziata(); notifyAll(); out.println("sveglio tutti "); out.flush(); } else{ wait(); out.println("sveglio "); out.flush(); } } public synchronized void run() { in = new Scanner(socket.getInputStream()); out = new PrintWriter(socket.getOutputStream()); out.println("Giocatore " + giocatore + " connesso "); out.flush(); controlloInizio(); }
Non stai usando nel modo corretto la sincronizzazione.
Per prima cosa i thread dovrebbero sincronizzarsi su un oggetto in comune a tutti. Quindi, NON su essi stessi e, di conseguenza, non ha alcun senso rendere sincronizzati il run() e, generalmente, i metodi dei thread. Ciò che dovrebbe essere sincronizzato è l'accesso alla risorsa condivisa.
In secondo luogo, il wait() dovrebbe essere posto sotto condizione e all'interno di un ciclo, in modo che se più thread vengono risvegliati, solo uno acquisisca il lock necessario e gli altri tornino in wait.
L'argomento "sincronizzazione" dei thread non è così semplice. Va studiato bene e capito esattamnte il meccanismo.
In linea di principio, la situazione può essere descritta in questo modo:
I metodi sincronizzati non sono quelli del thread. Il thread deve solo svolgere una funzione... a lui non interessa che qualcuno lo possa fermare e mettere in attesa.codice:class MioThread extends Thread { ... @Override public void run() { ... mioOggettoCondiviso.accedoAllaRisorsaCondivisa(); ... } } class MioOggettoCondiviso ... { ... public synchronized void accedoAllaRisorsaCondivisa() { while ( condizionePerBloccareIlThread ) { try { wait(); } catch (InterruptedException ie) { ie.printStackTrace(); } } ... // Parte di codice sottoposta a sincronizzazione notifyAll(); // Qui sblocco tutti... il primo che si sveglia vince } }
La wait() è all'interno di un ciclo condizionato. In questo modo, apena due o più thread si risvegliano, controllano tutti la condizione, ma solo il primo che acquisisce il nuovo lock proseguirà... gli altri torneranno in wait. Chiaramente la condizione deve essere semanticamente corretta con la logica del programma.
La notifyAll() la faccio, subito prima di lasciare la regione critica.
Ciao.![]()
"Perchè spendere anche solo 5 dollari per un S.O., quando posso averne uno gratis e spendere quei 5 dollari per 5 bottiglie di birra?" [Jon "maddog" Hall]
Fatti non foste a viver come bruti, ma per seguir virtute e canoscenza
Ma perchè in questo codice preso dal libro si effettua la wait direttamente sul run() qual'è la differenza? grazie
codice:class MioThread extends Thread { private int num; private int succ; private MioThread[] ref; private boolean stato; //true: attivo false: disattivo public MioThread(int num, int succ) { this.num = num; this.succ = succ; this.stato = (num == 0); } public void setArray(MioThread[] ar) { ref = ar; } public synchronized void attiva() { stato = true; notify(); // CON QUESTO FUNZIONA } public synchronized void run() { try{ while(!stato) wait(); Console.scriviStringa("MioThread "+num); }catch(InterruptedException e){ } if(succ!=-1) { ref[succ].attiva(); } } }
Quel codice è leggermente "più contorto".
La sincronizzazione viene fatta su un array di oggetti Thread condiviso e contenente i riferimenti di ciascun thread... cerca di partire con qualcosa di più semplice...
Ciao.![]()
"Perchè spendere anche solo 5 dollari per un S.O., quando posso averne uno gratis e spendere quei 5 dollari per 5 bottiglie di birra?" [Jon "maddog" Hall]
Fatti non foste a viver come bruti, ma per seguir virtute e canoscenza