|
|
|
![]() |
|
Strumenti |
![]() |
#1 |
Senior Member
Iscritto dal: Oct 2009
Città: Trento
Messaggi: 1682
|
[JAVA]Copiare/passare il riferimento di un'oggetto è thread safe?
Ciao a tutti, nel tempo libero mi sto dilettando a sviluppare una piccola applicazione Client-Server in java servendomi degli strumenti messi a disposizione per il multi-threading.
Sapete dirmi, nel caso l'oggetto in questione non sia final, se di un'oggetto condiviso tra più thread copiare il riferimento o passarlo come parametro sia thread-safe? Ad esempio ho un'oggetto condiviso in lettura/scrittura oppurtunamente sincronizzata tra più thread: OggettoA A = new OggettoA(); fare: OggettoA B = A; o FaiQualcosa(A); sia thred-safe o abbiano bisogno anchessi di sincronizzazione?
__________________
trattative ok: ZETA81, worgc001, Ri20x,coyote69,+Benito+,Bovirus,S@ibbu,vega05,andreagira,Andrea_yota,meli.j,MIKI,Super-Vegèta,bigtzunami,luciolux,theLux,gomax,attanasio,castigator222,DioSpada,semmy83,Talpa88,raizen89,Friskio TheBesT,coontrol86,davd89,Giankarlo,pariduzz86,joe79,ak72,lemming e fmartine ![]() Ultima modifica di Satshas : 06-07-2011 alle 11:34. |
![]() |
![]() |
![]() |
#2 | |
Senior Member
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
|
Quote:
Ma per essere sicuri bisognerebbe esaminare il codice. Se ti dovesse servire documentazione di riferimento, ti posto tre risorse utili: 1) trail sulla concurerncy nei Java Tutorials 2) javadoc del package java.util.concurrent (la parete titolata "Memory Consistency Properties") 3) capitolo 17 del Java Language Specifications (Threads and Locks)
__________________
As long as you are basically literate in programming, you should be able to express any logical relationship you understand. If you don’t understand a logical relationship, you can use the attempt to program it as a means to learn about it. (Chris Crawford) |
|
![]() |
![]() |
![]() |
#3 |
Senior Member
Iscritto dal: Oct 2009
Città: Trento
Messaggi: 1682
|
Grazie della risposta.
Trascendendo la correttezza o meno del codice in materia di sincronizzazione (dove s'intende proprio acquisire un lock in via esclusiva) che si potrebbe porre corretta per ipotesi iniziale, non riesco a trovare riferimenti sulle operazioni sul reference di un'oggetto nei thread, se non quando si parla di oggetti del tipo/o contenenti campi "final" che vanno inizializzati completamente (An object is considered to be completely initialized when its constructor finishes.) prima di essere usati da più threads. Cosa che ho sempre provveduto a fare per oggetti condivisi non "final" con l'aggiunta dei costrutti della sincronizzazione. Comunque per curiosità, il problema mi è nato nell'implementazione di un semplice sistema di login in cui un'array di oggetti Login contenenti due string ognuno per memorizzare nome utente e password, dopo essere stato inizializzato e riempito con i dati da un file, viene passato nel metodo init di ogni classe SlotUtente che gestisce a sua volta il ThreadSlotUtente, esplicitando che in questa fase tutti i thread sono fermi. Dopo avviato i thread del server, nel momento in cui arriva una nuova connessione viene lanciato un ThreadSlotUtente (quando altri ThreadSlotUtente possono essere già attivi ed usare Login) con parametro appunto l'array di Login. Ogni ThreadSlotUtente, ad un certo punto della sua fase di esecuzione, si occupa di verificare che i dati ricevuti via rete corrispondano ad un'effettivo utente già registrato con un codice del tipo: for(int C=0;C<NumeroLogins;C++){ synchronized(Login[C]){ if(NomeUtente.equals(Login[C].NomeUtente)) if(Password.equals(Login[C].Password)){ LoginTrovato = true; break; } } } ciò poteva anche essere ovviamente implementato scrivendo due metodi synchronized (Set)GetNomeUtente() e (Set)GetPassword() all'interno dell'oggetto Login ma ho preferito così per far sì che a thread fermi se devo effettuare operazioni sull'oggetto Login esse non debbano passare dal lock.
__________________
trattative ok: ZETA81, worgc001, Ri20x,coyote69,+Benito+,Bovirus,S@ibbu,vega05,andreagira,Andrea_yota,meli.j,MIKI,Super-Vegèta,bigtzunami,luciolux,theLux,gomax,attanasio,castigator222,DioSpada,semmy83,Talpa88,raizen89,Friskio TheBesT,coontrol86,davd89,Giankarlo,pariduzz86,joe79,ak72,lemming e fmartine ![]() Ultima modifica di Satshas : 06-07-2011 alle 16:29. |
![]() |
![]() |
![]() |
#4 |
Senior Member
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
|
Ciao, da questo spezzone di codice:
Codice:
for(int C=0; C<NumeroLogins; C++) { synchronized(Login[C]) { if(NomeUtente.equals(Login[C].NomeUtente)) if(Password.equals(Login[C].Password)) { LoginTrovato = true; break; } } } Significa forse che un qualsiasi Login potrebbe nel frattempo venire mutato da qualche altro thread? Intendo dire: se l'array Login non viene più mutato dopo l'inizializzazione iniziale, e se le singole istanze di Login che esso contiene non vengono più mutate a loro volta (nessun thread va a modificare i campi nomeUtente e Password) allora non è neccessario sincronizzare nulla, le letture sono tutte safe.
__________________
As long as you are basically literate in programming, you should be able to express any logical relationship you understand. If you don’t understand a logical relationship, you can use the attempt to program it as a means to learn about it. (Chris Crawford) Ultima modifica di banryu79 : 07-07-2011 alle 08:24. |
![]() |
![]() |
![]() |
#5 |
Senior Member
Iscritto dal: Oct 2009
Città: Trento
Messaggi: 1682
|
Le assunzioni che hai fatto sono corrette, infatti ho previsto che l'array Login possa cambiare in due scenari:
1)Fermo il server, che corrisponde a fermare tutti i thread, e ho necessità di reinizializzare tutti i dati compresi i Login.In questo caso ovviamente non ho bisogno di sincronizzazione. 2)Un nuovo utente si registra/modifica i propri dati Login mentre il server è attivo, e quindi lo sono tutti i thread tra cui potrebbero esserci N>=0 ThreadSlotUtente che stanno effettuando il login, e qui ho appunto bisogno di lock esclusivo Comunque ritornando IT sul discorso reference e tralasciando altre scelte implementative in cui potrei evitare di pormi la domanda, io passo al costruttore dei ThreadSlotUtente e copio su un riferimento locale l'array Login che nel frattempo può essere letto e/o modificato da altri ThreadSlotUtente o dal thread che si occupa delle registrazioni. E' confermato che ciò, o che il concetto in generale dato che può tornare utile, è thread-safe?
__________________
trattative ok: ZETA81, worgc001, Ri20x,coyote69,+Benito+,Bovirus,S@ibbu,vega05,andreagira,Andrea_yota,meli.j,MIKI,Super-Vegèta,bigtzunami,luciolux,theLux,gomax,attanasio,castigator222,DioSpada,semmy83,Talpa88,raizen89,Friskio TheBesT,coontrol86,davd89,Giankarlo,pariduzz86,joe79,ak72,lemming e fmartine ![]() Ultima modifica di Satshas : 07-07-2011 alle 11:16. |
![]() |
![]() |
![]() |
#6 | ||
Senior Member
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
|
Quote:
1) l'accesso alla singola istanza Login, a causa di potenziale mutazione concorrente da parte di un altro thread, il che capita quando un utente modifica i propri dati. 2) l'accesso all'array Login, a causa di potenziale mutazione concorrente da parte di un altro thread, il che capita quando un utente nuovo si registra (nuovo Login da aggiungere all'array e quindi nuovo array?) A questo punto penso ti converrebbe usare un java.util.concurrent.CopyOnWriteArrayList al posto dell'array di Login: è perfetto per condividere una collezione sulla quale si eseguono molti accessi in lettura e pochi/rari accessi in scrittura. In particolare potresti usare l'iterator restituito da questa collezione, che rappresenta lo "snapshot" dello stato della stessa al momento della sua chiamata. Devi poi comunque sincronizzare l'accesso al singolo Login, se può essere mutato da un'altro thread (punto 1) Ma forse a questo punto ti converrebbe progettare una classe thread-safe che incapsuli tutto il sistema logico di login (creazioneUtente - modificaUtente - cancellaUtente - utenteRegistrato) al suo interno ed esponga metodi ad-hoc per le varie operazioni. Quote:
Ripeto che forse ti faciliti la vita creandoti una classe ad-hoc, come sopra.
__________________
As long as you are basically literate in programming, you should be able to express any logical relationship you understand. If you don’t understand a logical relationship, you can use the attempt to program it as a means to learn about it. (Chris Crawford) |
||
![]() |
![]() |
![]() |
#7 |
Senior Member
Iscritto dal: Oct 2009
Città: Trento
Messaggi: 1682
|
Discorso ancora da decidere e implementare per quanto riguarda l'aggiunta di un utente perchè nel caso facessi un synchronized(Login) in effetti dovrei farlo anche nel ciclo che controlla nome utente e password.
Comunque proverò a leggere qualcosa per CopyOnWriteArrayList anche se vorrei evitare di fare la copia (se ho capito bene lo snapshot forse lo è) dato che potrebbe in effetti tornare utile. Per il chiarire sul discorso thread-safe sul reference, effettuo appunto una copia del reference non la copia dell'array.
__________________
trattative ok: ZETA81, worgc001, Ri20x,coyote69,+Benito+,Bovirus,S@ibbu,vega05,andreagira,Andrea_yota,meli.j,MIKI,Super-Vegèta,bigtzunami,luciolux,theLux,gomax,attanasio,castigator222,DioSpada,semmy83,Talpa88,raizen89,Friskio TheBesT,coontrol86,davd89,Giankarlo,pariduzz86,joe79,ak72,lemming e fmartine ![]() |
![]() |
![]() |
![]() |
#8 | ||
Senior Member
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
|
Quote:
Quote:
Io ti consiglio di wrappare tutto in una classe thread-safe, e poi condividerne un'istanza tra i vari thread. EDIT: non c'e problema prechè suppongo che il thread che esegue il costruttore di un ThreadSlotUtente sia sempre il main thread...
__________________
As long as you are basically literate in programming, you should be able to express any logical relationship you understand. If you don’t understand a logical relationship, you can use the attempt to program it as a means to learn about it. (Chris Crawford) Ultima modifica di banryu79 : 07-07-2011 alle 13:14. |
||
![]() |
![]() |
![]() |
Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 18:43.