Si sincronizza su un oggetto specifico, o qualche oggetto serratura statico designato, o l'oggetto classe (che avviene quando i metodi statici sono dichiarati essere sincronizzato):
class X {
private static final Object lock = new Object();
public void oneAtATime() {
synchronized (lock) {
// Do stuff
}
}
}
class Y {
public void oneAtATime() {
synchronized (Y.class) {
// Do stuff
}
}
}
Ogni variante ha i suoi vantaggi e svantaggi ; il blocco sulla classe consente ad altri codici, al di fuori della classe, di utilizzare lo stesso blocco per i propri motivi (che consente di orchestrare più sincronizzazione di alto livello rispetto a ciò che si fornisce) mentre l'approccio static final Object lock
consente di vietarlo bloccando il blocco campo privato (che rende più facile ragionare sul blocco ed evitare il codice dal deadlock perché qualcun altro ha scritto un codice errato).
Si potrebbe naturalmente anche usare un meccanismo di sincronizzazione dal java.util.concurrent
, come espliciti Lock
s, che forniscono maggiore controllo sulla bloccaggio (e ReentrantLock
attualmente esegue un po 'meglio di serrature impliciti sotto alta contesa).
Edit: Si noti che/serrature globali statici non sono un ottimo modo per andare - significa ogni istanza della classe mai creato sarà essenzialmente essere legato a tutti gli altri casi (che, a parte che lo rende più difficile da testare o leggere il codice, può danneggiare gravemente la scalabilità). Suppongo che tu faccia questo per sincronizzare un qualche tipo di stato globale? In tal caso, prenderei in considerazione l'idea di inserire lo stato globale/statico in una classe e implementare la sincronizzazione per istanza anziché a livello globale.
Invece di qualcosa di simile a questo:
class Z {
private static int state;
public void oneAtATime(){
synchronized (Z.class) {
state++;
}
}
}
fare in questo modo:
class State {
private int value;
public synchronized void mutate(){ value++; }
}
class Z {
private final State state;
public Z(State state){
this.state = state;
}
public void oneAtATime(){
state.mutate();
}
}
// Usage:
State s1 = new State(), s2 = new State();
Z foo = new Z(s1);
Z bar = new Z(s1);
Z frob = new Z(s2);
Z quux = new Z(s2);
Ora foo
e bar
sono ancora legati gli uni agli altri, ma possono lavorare indipendentemente da frob
e quux
.
Puoi spiegare perché è necessario farlo? Ho la sensazione che potresti attaccare il problema sbagliato. La necessità di sincronizzare le chiamate di metodo attraverso * istanze completamente diverse della tua classe * sembra che il vero problema sia da qualche altra parte. –