sincronizar en un objeto específico, o bien un objeto de bloqueo estático designado, o la clase de objeto (lo que ocurre cuando se declaran los métodos estáticos para ser sincronizado):
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
}
}
}
Cada variante tiene sus propias ventajas y desventajas ; el bloqueo de la clase permite que otro código, fuera de la clase, use el mismo bloqueo por sus propios motivos (lo que le permite orquestar más sincronización de alto nivel que la que proporciona) mientras que el método static final Object lock
le permite prohibirlo haciendo el bloqueo campo privado (lo que hace que sea más fácil razonar sobre el bloqueo y evitar que su código se bloquee porque alguien más escribió código incorrecto).
Por supuesto podría también utilizar algún mecanismo de sincronización de java.util.concurrent
, como explícitos Lock
s, que proporcionan un mayor control de bloqueo (y ReentrantLock
actualmente realiza un poco mejor que los bloqueos implícitos en condiciones de alta contención).
Editar: Tenga en cuenta que las cerraduras/globales estáticas no son una gran manera de ir - que significa que cada instancia de la clase jamás creado verán esencialmente ligada a todos los demás casos (que, aparte de que fuera más difícil de probar o leer el código, puede dañar gravemente la escalabilidad). Supongo que haces esto para sincronizar algún tipo de estado global. En ese caso, consideraría incluir ese estado global/estático en una clase e implementar la sincronización por instancia en lugar de implementarla globalmente.
En lugar de algo como esto:
class Z {
private static int state;
public void oneAtATime(){
synchronized (Z.class) {
state++;
}
}
}
hacerlo de esta manera:
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);
Ahora foo
y bar
todavía están vinculados entre sí, pero pueden trabajar independientemente de frob
y quux
.
¿Puede explicar por qué necesita hacer esto? Tengo la sensación de que podrías estar atacando el problema equivocado. Necesitar sincronizar llamadas de método en * instancias completamente diferentes de su clase * parece que el problema real está en otro lugar. –