Bloque sincronizado de Java para .class

Respuestas:

144

El fragmento synchronized(X.class)usa la instancia de la clase como monitor. Como solo hay una instancia de clase (el objeto que representa los metadatos de la clase en tiempo de ejecución), un hilo puede estar en este bloque.

Con synchronized(this)el bloque está protegido por la instancia. En cada caso, solo un hilo puede entrar en el bloque.

synchronized(X.class)se utiliza para asegurarse de que haya exactamente un hilo en el bloque. synchronized(this)asegura que haya exactamente un hilo por instancia. Si esto hace que el código real en el bloque sea seguro para subprocesos, depende de la implementación. Si mutar, solo el estado de la instancia synchronized(this)es suficiente.

Thomas Jung
fuente
6
"Pueden entrar en el bloque tantos hilos como instancias" implica que la segunda forma actúa como un semáforo, lo cual no es cierto. Debería decir algo como: "sincronizado (esto) asegura que solo un hilo pueda entrar al bloque para una instancia determinada de la clase".
liwp
Corregido. Tenía la intención de decir eso.
Thomas Jung
2
¿Cuál es la instancia de clase frente a la instancia?
Weishi Zeng
Entonces, si tiene un método estático y no queremos sincronizar todo su cuerpo, entonces sincronizamos (esto) no es bueno, en cambio sincronizado (Foo.class) es apropiado. ¿Está bien?
krupal.agile
84

Para agregar a las otras respuestas:

static void myMethod() {
  synchronized(MyClass.class) {
    //code
  }
}

es equivalente a

static synchronized void myMethod() {
  //code
}

y

void myMethod() {
  synchronized(this) {
    //code
  }
}

es equivalente a

synchronized void myMethod() {
  //code
}
Jorn
fuente
12
Me tomó una segunda lectura darme cuenta de que los dos primeros ejemplos tienen la palabra clave "estática". Solo señalándolo a otros que pueden haber visto esto y no lo hayan visto. Sin la palabra clave estática, los dos primeros ejemplos no serían iguales.
kurtzbot
1
¡Esos ejemplos NO son equivalentes! Los métodos sincronizados se "sincronizan" como un agujero cuando un hilo intenta llamar a los métodos. Los bloques, por otro lado, pueden tener código por encima y por debajo de ellos, que se puede ejecutar desde múltiples subprocesos. ¡Solo se sincronizan dentro del bloque! ¡Eso no es lo mismo!
JacksOnF1re
public static Singleton getInstance () {if (instancia == nulo) {sincronizado (Singleton.class) {instancia = nuevo Singleton (); }} instancia de retorno; }
JacksOnF1re
2
El punto es que no es ningún código fuera de los synchronizedbloques. Eso los hace equivalentes. Si cambia un ejemplo, de hecho ya no es el mismo.
Jorn
23

No, el primero obtendrá un bloqueo en la definición de clase de MyClass, no en todas las instancias. Sin embargo, si se usa en una instancia, esto bloqueará efectivamente todas las demás instancias, ya que comparten una sola definición de clase.

El segundo obtendrá un bloqueo solo en la instancia actual.

En cuanto a si esto hace que sus objetos sean seguros para subprocesos, esa es una pregunta mucho más compleja: ¡necesitaríamos ver su código!

David M
fuente
1
sí, MyClass.class podría ser cualquier variable estática y tener el mismo efecto.
pstanton
0

Sí, lo hará (en cualquier función / bloque sincronizado).

Estuve preguntándome sobre esta pregunta durante un par de días para mí (en realidad, en kotlin). Finalmente encontré una buena explicación y quiero compartirla:

El bloqueo de nivel de clase evita que varios subprocesos entren en un bloque sincronizado en cualquiera de todas las instancias disponibles de la clase en tiempo de ejecución. Esto significa que si en tiempo de ejecución hay 100 instancias de DemoClass, entonces solo un hilo podrá ejecutar demoMethod () en cualquiera de las instancias a la vez, y todas las demás instancias se bloquearán para otros hilos.

El bloqueo de nivel de clase siempre debe realizarse para que los subprocesos de datos estáticos sean seguros. Como sabemos que la palabra clave estática asocia datos de métodos a nivel de clase, utilice el bloqueo en campos o métodos estáticos para hacerlo a nivel de clase.

Además de notar por qué .class . Es solo porque .classes equivalente a cualquier variable estática de clase similar a:

private final static Object lock = new Object();

donde el nombre de la variable de bloqueo es clase y el tipo es Clase <T>

Leer más: https://howtodoinjava.com/java/multi-threading/object-vs-class-level-locking/

vitalii
fuente