Sie synchronisieren zu einem bestimmten Objekt, entweder einige bezeichneten statischen Sperrobjekt oder das Klassenobjekt (was geschieht, wenn statische Methoden deklariert sind synchronisiert werden):
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
}
}
}
Jede Variante hat seine eigenen Vor- und Nachteile ; Durch das Sperren der Klasse kann anderer Code außerhalb der Klasse die gleiche Sperre für seine eigenen Gründe verwenden (wodurch er eine höhere Synchronisierung als die von Ihnen gebotene Orchestrierung durchführen kann), während die Methode static final Object lock
die Sperre durch Sperren zulässt field private (was es einfacher macht, über die Sperrung nachzudenken und zu vermeiden, dass Ihr Code blockiert wird, weil jemand anderen schlechten Code geschrieben hat).
Sie könnte natürlich auch eine gewissen Synchronisationsmechanismus von java.util.concurrent
, wie expliziten Lock
s verwenden, die sie über mehr Kontrolle bieten Sperren (und ReentrantLock
zur Zeit führt ein wenig besser als implizite Sperren unter hohen Konkurrenz).
Edit: Beachten Sie, dass statische/global Sperren zu gehen nicht eine gute Möglichkeit, - es jede Instanz der Klasse bedeutet immer zu jedem anderen Fall im wesentlichen gebunden werden (die, beiseite geschaffen werden sie sie davon schwerer zu testen oder den Code zu lesen, kann die Skalierbarkeit ernsthaft beeinträchtigen). Ich nehme an, dass Sie das tun, um eine Art globalen Staat zu synchronisieren? In diesem Fall würde ich in Betracht ziehen, den globalen/statischen Status stattdessen in eine Klasse einzufügen und die Synchronisierung pro Instanz statt global zu implementieren.
Statt etwas wie folgt aus:
class Z {
private static int state;
public void oneAtATime(){
synchronized (Z.class) {
state++;
}
}
}
es wie folgt tun:
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);
Jetzt foo
und bar
sind miteinander noch gebunden, sie können aber von frob
und quux
unabhängig arbeiten.
Können Sie erklären, warum Sie dies tun müssen? Ich habe das Gefühl, dass du das falsche Problem angreifst. Das Synchronisieren von Methodenaufrufen über * völlig unterschiedliche Instanzen Ihrer Klasse * klingt wie das eigentliche Problem woanders. –