2013-04-05 20 views
11

Ho letto alcuni codice Java, e hanno trovato queste funzioni:java parola chiave sincronizzata necessaria sul metodo getter/setter primitivo?

synchronized void setConnected(boolean connected){ 
    this.connected = connected; 
} 

synchronized boolean isConnected(){ 
    return connected; 
} 

mi chiedo se la sincronizzazione ha un senso qui, o semplicemente autore non ha capito la necessità di parola chiave sincronizzato?

Suppongo che sincronizzato sia inutile qui. O mi sbaglio?

+0

Il modificatore sincronizzato ha senso solo se più di un thread sta per tentare di accedere alla variabile 'connected' - almeno questa è la mia comprensione. –

+0

Si prega di consultare http://stackoverflow.com/questions/11459543/java-synchronized-getters-and-setters. Risponde alla tua domanda e la inserisce piacevolmente in un contesto più ampio. – prashant

+2

leggi questi Q + A http://stackoverflow.com/questions/11459543/java-synchronized-getters-and-setters – Zelldon

risposta

19

La parola chiave synchronized è un modo per garantire la sicurezza del thread. Attenzione: c'è (molto) più sicurezza del thread che deadlock, o aggiornamenti mancanti a causa di due thread che incrementano un int senza sincronizzazione.

Si consideri la seguente classe:

class Connection { 
    private boolean connected; 
    synchronized void setConnected(boolean connected){ 
    this.connected = connected; 
    } 
    synchronized boolean isConnected(){ 
    return connected; 
    } 
} 

Se più thread condividono un'istanza di Connection e un thread chiama setConnected(true), senza synchronized è possibile che altri thread continuo a vedere isConnected() == false. La parola chiave synchronized garantisce che tutti i thread vedano il valore corrente del campo.

In termini più tecnici, la parola chiave synchronized assicura una barriera di memoria (suggerimento: google).

In più: ogni scrittura effettuata prima di rilasciare un monitor (cioè, prima di lasciare un blocco synchronized) è garantita per essere vista da ogni lettura effettuata dopo aver acquisito lo stesso monitor (cioè, dopo aver inserito un blocco di sincronizzazione sullo stesso oggetto). In Java, c'è qualcosa chiamato , prima di (suggerimento: google), che non è così banale come "Ho scritto il codice in questo ordine, quindi le cose vengono eseguite in questo ordine". L'utilizzo di synchronized è un modo per stabilire una relazione di successo prima e garantire che i thread vedano la memoria come ci si aspetterebbe che fossero visibili.

Un altro modo per ottenere le stesse garanzie, in questo caso, sarebbe eliminare la parola chiave synchronized e contrassegnare il campo volatile. Le garanzie fornite da volatile sono le seguenti: tutte le scritture effettuate da un thread prima di una scrittura volatile sono garantite per essere visibili a un thread dopo una successiva lettura volatile dello stesso campo.

Come nota finale, in questo caso particolare, potrebbe essere preferibile utilizzare un campo volatile anziché synchronized di accesso, in quanto i due approcci offrono le stesse garanzie e l'approccio -field volatile permette accessi simultanei al campo da diversi thread (che potrebbe migliorare le prestazioni se la versione synchronized presenta troppa contesa).

+0

Tuttavia, alcuni considerano una pratica leggermente migliore per la sincronizzazione su un campo finale, come suggerito da Mr. Skeet a questo thread: http://stackoverflow.com/questions/6910807/synchronization-of-non-final-field –

+0

La mia domanda è forse stupida, ma il tuo booleano non dovrebbe essere "volatile"? – Pith

+0

@pith: no, dal momento che tutti gli accessi ad esso (cioè, tutte le letture e le scritture) vengono eseguite all'interno dei metodi sincronizzati. –

2

L'autore ha probabilmente progettato il codice con un approccio multi-thread in mente. Ciò significa che i metodi sono sincronizzati e più di un thread non sarà in grado di accedere contemporaneamente al codice sincronizzato sulla stessa istanza dell'oggetto.

7

Qui è necessaria la sincronizzazione per evitare errori di coerenza della memoria, vedere http://docs.oracle.com/javase/tutorial/essential/concurrency/memconsist.html. Anche se in questo caso concreto volatile sarebbe molto più efficiente soluzione

private volatile boolean connected; 

void setConnected(boolean connected){ 
    this.connected = connected; 
} 

boolean isConnected(){ 
    return connected; 
} 
Problemi correlati