2012-01-05 22 views
10

Este es un sucesor de mi pregunta anterior, Is this variable being safely accessed by using synchronization?"synchronized (this)" vs. "synchronized ((BaseClass) this)" en Java?

Para el siguiente programa,

Class SubClassB extends SuperClassA { 
    protected int c; 

    public void inc() { 
      synchronized (this) { 
       c++; 
      } 
    } 

    public void dec() { 
      synchronized ((SuperClassA) this) { 
       c--; 
      } 
    } 
} 

se accedería hilo de seguridad del mostrador "c"? No estoy seguro de que en el método "dec()", ¿el SuperClassA arroja "esta" referencia como un objeto válido para el bloque sincronizado? En caso afirmativo, ¿bloquearían los dos bloques sincronizados el mismo "objeto"? (Como me parece que "(SuperClassA) esto" no es igual a "esto")

Este extraño código simulado proviene del siguiente ejemplo de la vida real donde SuperClassA es una clase base que no debe modificarse,

Class SuperClassA { 
    protected int c; 

    public void dec() { 
      synchronized (this) { 
       c--; 
      } 
    } 
} 

Class SubClassB extends SuperClassA { 

    public void inc() { 
      synchronized (this) { 
       c++; 
      } 
    } 

    public void dec() { 
      super.dec(); 
    } 
} 

en este ejemplo, el método de "DEC()" en SubClassB llamadas a métodos de su superclase "DEC()" que lleva a cabo un bloqueo para un objeto "this" que supongo que ser "SuperClassA.this". Si el objeto bloqueado en el método "inc()" de SubClassB no es exactamente el mismo que el objeto bloqueado en el método "dec()" de SubClassB, entonces me pregunto si el subtema heredado "c" en SubClassB NO puede ser accedido de forma segura por diferentes subprocesos . Siento que hay algunas ambigüedades al usar la referencia "this" en bloques sincronizados.

En el ejemplo de la vida real, si quiero contador "c" de SubClassB ser seguro para subprocesos, necesito para añadir una cuadra más sincronizada en su método "DEC()", de esta manera,

Class SubClassB extends SuperClassA { 

    public void inc() { 
      synchronized (this) { 
       c++; 
      } 
    } 

    public void dec() { 
      synchronized (this) { 
       super.dec(); 
      } 
    } 
} 

¡Pero parece que ese bloque agregado no es elegante y puede ser redundante!

¿Alguien tiene algunas ideas sobre estas preguntas? Gracias por adelantado.

Lawrence

Respuesta

5

¿Se puede acceder al contador "c" thread safe?

Sí, está utilizando el mismo objeto de bloqueo.

No estoy seguro de que en el método "dec()", ¿el SuperClassA emite "esta" referencia como un objeto válido para el bloque sincronizado?

Sí.

En caso afirmativo, ¿bloquearían los dos bloques sincronizados el mismo "objeto"? (Como me parece que "(SuperClassA) esto" no es igual a "esto")

Sí. Incluso si convierte la instancia en algo a lo que se puede convertir (incluso en Objeto), seguirá refiriéndose al mismo objeto.

[...] ¡Pero parece que ese bloque adicional no es elegante y puede ser redundante!

Es redundante. Se requiere sincronización adicional solo si llama a múltiples métodos sincronizados y el efecto combinado debe ser atómico.

+0

Gracias por sus respuestas. – user1129812

2

Los tres ejemplos son correcta en lo que se refiere a la sincronización.

  1. Solo hay un monitor asociado a cualquier objeto.
  2. Casting this a una clase base dentro de synchronized no hace ninguna diferencia.
  3. Para el mismo objeto, no importa si se invoca synchronized(this) en el contexto de la clase derivada o la clase base: el mismo bloqueo se usa en ambos casos.
+0

Gracias por su rápida respuesta y me recuerda que solo hay un monitor con cualquier objeto. – user1129812

6

El código es thread-safe, porque (SomeObject) this adn this son el mismo objeto. Un elenco no transforma un objeto en otro objeto.

El código carece de encapsulamiento, sin embargo, porque permite que cualquier subclase tenga acceso al campo c protegido de manera no sincronizada. Por lo tanto, cualquier subclase puede usar c++ o c-- sin ninguna sincronización. El campo debe ser privado.

+0

Gracias por recordarme que el contador "c" debe declararse "privado". – user1129812

3

me parece que "(SuperClassA) esto" no es igual a "este"

incorrecto; la sincronización se realiza en objetos, y la conversión solo cambia el tipo de tiempo de compilación, no tiene ningún efecto sobre la identidad del objeto.

Por lo tanto, no tiene que agregar una sincronización adicional en la subclase.

+0

Ahora sé que "(SuperClassA) this" y "this" son de tipo de tiempo de compilación diferente pero mantienen el mismo bloqueo en el bloque sincronizado. – user1129812

Cuestiones relacionadas