C'è una sottile distinzione tra i due. Diamo un'occhiata al seguente codice di esempio.
public class Foo {
private static Object lockFunction = new Object();
private static Bar myBar = new Bar();
public void fooFunc(float someValue) {
synchronized (lockFunction){ //locking against the function
fooPrivates(someValue);
}
}
public void fooFunc2(float someValue1) {
myBar.setValue(someValue2); //Danger! unlocked access to myBar
}
private void fooPrivates(float someValue){
myBar.setValue(someValue);
}
}
public static class Bar {
private static Object lockBarData = new Object();
private float myValue;
public float getValue() {
synchronized (lockBarData) { //technically not necessary since it's a read operation
return myValue;
}
}
public void setValue(value) {
synchronized (lockBarData) { //locking against the data
myValue = value;
}
}
}
Il pericolo con lockObject
è che sta controllando l'accesso alla chiamata della funzione fooPrivate
. Non esercita alcun controllo su altre funzioni che accedono a Bar
object myBar
. E se ti capita di avere copie statiche di myBar
, avrai una singola copia di myBar
utilizzata da più copie di Foo
.
lockBar
invece controlla l'accesso alla variabile privata myValue
all'interno della classe Bar
.
In un esempio banale come quello sopra, funzioneranno entrambi perché è possibile assicurarsi che funzioni come FooFunc2 semplicemente non possano lavorare in questo modo. Ma in un'applicazione complessa, multi-thread, diventa più facile che sorgano situazioni sottili in cui myBar viene manipolato senza essere controllato da un blocco.
Nella mia esperienza, il blocco dei dati è il modo migliore per andare.
Quando blocchi la funzione, devi assicurarti che tutto ciò che accede a quella funzione funzioni allo stesso modo. Introduce maggiori problemi di governance al fine di garantire che il codice non conforme non entri nel codice base. Un altro problema con il blocco della funzione è che in genere si tiene il blocco per un periodo di tempo più lungo di quello che si farebbe se si bloccasse contro i dati.
Bloccarsi contro i dati rende più semplice nascondere l'implementazione dell'oggetto dati dagli utenti dei dati. Anche nel banale esempio precedente, Foo
non sa necessariamente (o cura!) Che Bar
deve avere un blocco in posizione prima che tutto possa essere fatto con myValue
.