Métodos estáticos sincronizados de Java: bloqueo en objeto o clase

148

La documentación de Java dice:

No es posible que dos invocaciones de métodos sincronizados en el mismo objeto se intercalen.

¿Qué significa esto para un método estático? Dado que un método estático no tiene ningún objeto asociado, ¿se bloqueará la palabra clave sincronizada en la clase, en lugar del objeto?

jbu
fuente

Respuestas:

129

Dado que un método estático no tiene ningún objeto asociado, ¿ se bloqueará la palabra clave sincronizada en la clase, en lugar del objeto?

Si. :)

OscarRyz
fuente
81
Responda Elaborar para que todos puedan entender.
Madhu
66
@Madhu. Significa que si tiene 2 o más métodos sincronizados en la misma clase, ambos no pueden ejecutarse al mismo tiempo, incluso cuando hay varias instancias de esa clase. El bloqueo es esencialmente lo mismo que el bloqueo en Object.class para cada método sincronizado.
Steven
Esta respuesta es incorrecta ( thises el bloqueo adquirido en los métodos de instancia), corríjalo Oscar.
vemv
1
@vemv La pregunta se refiere a los métodos de clase, no a los métodos de instancia.
OscarRyz
23
@vemv Bueno, sí, para entender la respuesta, primero debes leer la pregunta.
OscarRyz
199

Solo para agregar un pequeño detalle a la respuesta de Oscar (¡agradablemente sucinta!), La sección relevante sobre la Especificación del lenguaje Java es 8.4.3.6, 'Métodos sincronizados' :

Un método sincronizado adquiere un monitor ( §17.1 ) antes de ejecutarse. Para un método de clase (estático), se utiliza el monitor asociado con el objeto Class para la clase del método. Para un método de instancia, se usa el monitor asociado con esto (el objeto para el que se invocó el método).

Cowan
fuente
17
Útil, estaba buscando esa cita +1
OscarRyz
80

Un punto que debe tener cuidado (varios programadores generalmente caen en esa trampa) es que no existe un vínculo entre los métodos estáticos sincronizados y los métodos no estáticos sincronizados, es decir:

class A {
    static synchronized f() {...}
    synchronized g() {...}
}

Principal:

A a = new A();

Hilo 1:

A.f();

Hilo 2:

a.g();

f () yg () no están sincronizados entre sí y, por lo tanto, pueden ejecutarse de manera totalmente simultánea.

jfpoilpret
fuente
18
pero qué pasa si g () está mutando alguna variable estática que f () está leyendo. ¿Cómo hacemos que ese hilo sea seguro? ¿Adquirimos explícitamente un bloqueo en la clase entonces?
Baskin
22
Sí, su método no estático debe sincronizar de forma explícita en la clase en sí (es decir, synchronized (MyClass.class) {...}.
jfpoilpret
@jfpoilpret "synchronized (MyClass.class) {...}" es equivalente a hacer que este método esté sincronizado estático, ¿verdad?
crazymind
15

A menos que implemente g () de la siguiente manera:

g() {
    synchronized(getClass()) {
        ...
    }
}

Este patrón también me resulta útil cuando quiero implementar la exclusión mutua entre diferentes instancias del objeto (que es necesario cuando se accede a un recurso externo, por ejemplo).

tratar de atrapar finalmente
fuente
63
Tenga en cuenta que en realidad puede haber una posibilidad de algunos errores muy sutiles y desagradables aquí. Remember getClass()devuelve el tipo de tiempo de ejecución ; si subclasifica la clase, la clase principal y la clase secundaria se sincronizarán en diferentes bloqueos. synchronized(MyClass.class)es el camino a seguir si necesita asegurarse de que todas las instancias usen el mismo bloqueo.
Cowan
4

Eche un vistazo a la página de documentación de Oracle sobre bloqueos intrínsecos y sincronización

Quizás se pregunte qué sucede cuando se invoca un método estático sincronizado, ya que un método estático está asociado a una clase, no a un objeto. En este caso, el subproceso adquiere el bloqueo intrínseco para el objeto Clase asociado con la clase . Por lo tanto, el acceso a los campos estáticos de la clase se controla mediante un bloqueo que es distinto del bloqueo para cualquier instancia de la clase .

Ravindra babu
fuente
2

Un método estático también tiene un objeto asociado. Pertenece al archivo Class.class en el kit de herramientas JDK. Cuando el archivo .class se carga en la memoria RAM, Class.class crea una instancia llamada objeto de plantilla.

Por ejemplo: cuando intentas crear un objeto a partir de una clase de cliente existente como

Customer c = new Customer();

La clase Customer.class se carga en la RAM. En ese momento Class.class en el kit de herramientas JDK crea un Objeto llamado objeto Template y carga ese Customer.class en ese objeto template. Los miembros estáticos de ese Customer.class se convierten en atributos y métodos en ese objeto template.

Entonces, un método o atributo estático también tiene un objeto

Pahansith Gunathilake
fuente
2

Los ejemplos a continuación brindan más claridad entre el bloqueo de clase y objeto, espero que el ejemplo a continuación ayude a otros también :)

Por ejemplo, tenemos los siguientes métodos: una clase de adquisición y otra bloqueo de objeto de adquisición:

public class MultiThread {

    public static synchronized void staticLock() throws InterruptedException {
        for (int i = 0; i < 10; i++) {
            Thread.sleep(100);
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
    }

    public synchronized void objLock() throws InterruptedException {
        for (int i = 0; i < 10; i++) {
            Thread.sleep(100);
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
    }
}

Entonces, ahora podemos tener los siguientes escenarios:

  1. Cuando los hilos que usan el mismo objeto intentan acceder al método objLock OR al staticLock mismo tiempo (es decir, ambos hilos intentan acceder al mismo método)

    Thread-0 0
    Thread-0 1
    Thread-0 2
    Thread-0 3
    Thread-0 4
    Thread-1 0
    Thread-1 1
    Thread-1 2
    Thread-1 3
    Thread-1 4
  2. Cuando los hilos que usan el mismo objeto intentan acceder staticLocky objLockmétodos al mismo tiempo (intenta acceder a diferentes métodos)

    Thread-0 0
    Thread-1 0
    Thread-0 1
    Thread-1 1
    Thread-0 2
    Thread-1 2
    Thread-1 3
    Thread-0 3
    Thread-0 4
    Thread-1 4
  3. Cuando los hilos que utilizan objetos diferentes intentan acceder al staticLockmétodo

    Thread-0 0
    Thread-0 1
    Thread-0 2
    Thread-0 3
    Thread-0 4
    Thread-1 0
    Thread-1 1
    Thread-1 2
    Thread-1 3
    Thread-1 4
  4. Cuando los hilos que utilizan objetos diferentes intentan acceder al objLockmétodo

    Thread-0 0
    Thread-1 0
    Thread-0 1
    Thread-1 1
    Thread-0 2
    Thread-1 2
    Thread-1 3
    Thread-0 3
    Thread-0 4
    Thread-1 4
Ravi
fuente
0

Para aquellos que no están familiarizados, el método sincronizado estático bloqueado en el objeto de clase, por ejemplo, para la clase de cadena, su String.class, mientras que el método sincronizado de instancia se bloquea en la instancia actual de Object denotada por "esta" palabra clave en Java. Dado que ambos objetos son diferentes, tienen un bloqueo diferente, por lo que mientras un subproceso está ejecutando el método estático sincronizado, otro subproceso en Java no necesita esperar a que ese subproceso regrese, sino que adquirirá un bloqueo separado, el byte denotado .class literal y entrará en Método sincronizado estático.

Pragya
fuente