2012-01-05 15 views
10

Questo è un successore della mia domanda precedente, Is this variable being safely accessed by using synchronization?"sincronizzato (questo)" contro "sincronizzato ((BaseClass) questo" in Java?

Per il seguente programma,

Class SubClassB extends SuperClassA { 
    protected int c; 

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

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

sarebbe il contatore "c" è accessibile thread-safe? Non sono sicuro che nel metodo "dec()", la cast di SuperClassA "this" faccia riferimento a un oggetto valido per il blocco sincronizzato? Se sì, i due blocchi sincronizzati bloccerebbero lo stesso oggetto "questo"? (Come mi sembra che "(SuperClassA) questo" non è uguale a "questo")

Questo strano codice simulato deriva dal seguente esempio di vita reale in cui SuperClassA è una classe base che non dovrebbe essere modificata,

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(); 
    } 
} 

in questo esempio, il metodo "DEC()" in SubClassB chiama metodo sua superclasse "DEC()" che esegue una serratura per un "questo" oggetto che supponiamo essere "SuperClassA.this". Se l'oggetto bloccato nel metodo "inc()" di SubClassB non è esattamente uguale all'oggetto bloccato nel metodo "dec()" di SubClassB, allora mi chiedo se il contatore ereditato "c" in SubClassB NON possa essere acceduto in modo sicuro da thread diversi . Sento che ci sono alcune ambiguità nell'usare il riferimento "questo" nei blocchi sincronizzati.

Nell'esempio vita reale, se voglio contatore "c" di SubClassB essere thread-safe, ho bisogno di aggiungere un blocco più sincronizzato nel suo metodo "DEC()", in questo modo,

Class SubClassB extends SuperClassA { 

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

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

Ma sembra che tale blocco aggiunto non sia elegante e potrebbe essere ridondante!

Qualcuno ha qualche idea su queste domande. Grazie in anticipo.

Lawrence

risposta

5

Il contatore "c" può accedere al thread sicuro?

Sì, sta utilizzando lo stesso oggetto di blocco.

Non sono sicuro che nel metodo "dec()", la cast di SuperClassA "questo" faccia riferimento a un oggetto valido per il blocco sincronizzato?

Sì.

Se sì, i due blocchi sincronizzati bloccano lo stesso oggetto "questo"? (Per quanto mi sembra che "(SuperClassA) questo" non è uguale a "questo")

Sì. Anche se lanci l'istanza su qualcosa che può essere castata (anche su Object), farà comunque riferimento allo stesso oggetto.

[...] Ma sembra che tale blocco aggiunto non sia elegante e potrebbe essere ridondante!

È ridondante. La sincronizzazione aggiuntiva è necessaria solo se si chiamano più metodi sincronizzati e l'effetto combinato deve essere atomico.

+0

Grazie per le vostre risposte. – user1129812

2

Tutti e tre gli esempi sono corrette per quanto sincronizzazione è interessato.

  1. C'è un solo monitor associato a qualsiasi oggetto.
  2. La trasmissione this a una classe base all'interno di synchronized non fa alcuna differenza.
  3. Per lo stesso oggetto, non importa se synchronized(this) viene richiamato nel contesto della classe derivata o della classe base: lo stesso blocco viene utilizzato in entrambi i casi.
+0

Grazie per la vostra risposta veloce e ricordandomi che c'è un solo monitor con qualsiasi oggetto. – user1129812

6

Il codice è thread-safe, perché (SomeObject) this adn this sono lo stesso oggetto. Un cast non trasforma un oggetto in un altro oggetto.

Tuttavia, il codice non ha incapsulamento perché consente a qualsiasi sottoclasse di accedere al campo protetto c in modo non sincronizzato. Pertanto, qualsiasi sottoclasse potrebbe utilizzare c++ o c-- senza alcuna sincronizzazione. Il campo dovrebbe essere privato.

+0

Grazie per avermi ricordato che il contatore "c" deve essere dichiarato "privato". – user1129812

3

mi sembra che "(SuperClassA) questo" non è uguale a "questo"

sbagliato; la sincronizzazione viene eseguita sugli oggetti e il cast cambia solo il tipo in fase di compilazione, non ha alcun effetto sull'identità dell'oggetto.

Pertanto, non è necessario aggiungere una sincronizzazione aggiuntiva nella sottoclasse.

+0

Ora so che "(SuperClassA) questo" e "questo" sono di tipo di compilazione diverso ma mantengono lo stesso blocco nel blocco sincronizzato. – user1129812