2013-03-12 13 views
39

Diciamo che ho un metodo sincronizzato su qualche classe:Sostituzione di metodi sincronizzati in Java

abstract class Foo { 
    public synchronized void foo() { // synchronized! 
     // ... 
    }; 
} 

e mi escludeva che senza utilizzare il modificatore sincronizzato:

class Bar extends Foo { 
    @Override 
    public void foo() {    // NOT synchronized! 
     super.foo(); 
     // ... 
    } 
} 

Ho un paio di domanda specifica riguardante questo scenario:

  1. Il metodo di override b E anche implicitamente sincronizzato?
  2. In caso contrario, è possibile sincronizzare il numero super?
  3. Se non è presente la chiamata super, verrà sincronizzato qualcosa?
  4. C'è un modo per forzare un metodo di sovrascrittura per utilizzare synchronized (ho notato che le definizioni di metodo astratto o le definizioni di metodo all'interno di un'interfaccia non consentono la parola chiave sincronizzata)?
+0

Vedi http://stackoverflow.com/questions/12684850/how-can-i-ensure-that-an- overridden-method-is-synchronized – rgettman

+1

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4294756 Synchronized non fa parte della firma del metodo, ma parte dell'implementazione del metodo. – flup

risposta

41
public synchronized void foo() { // synchronized! 
    // ... 
}; 

è essenzialmente lo stesso di:

public void foo() { 
    synchronized (this) { // synchronized! 
     // ... 
    } 
}; 

Il secondo è più esplicito, quindi vorrei generale suggerirei di usare quella forma. O meglio usando un lock che è un campo privato invece dell'oggetto "esterno".

Quindi: 1. No. 2. Sì. 3. No. 4. Contrassegnare il metodo final e chiamare un metodo protected che potrebbe essere sovrascritto.

public final void foo() { 
    synchronized (this) { 
     fooImpl(); 
    } 
}; 
protected void fooImpl() { 
    // ... 
} 

Come sempre, si potrebbe star meglio con delegazione piuttosto che sottoclasse.

+0

+1 È un ottimo modo di guardarlo! Grazie! –

+0

usando fooImpl è il modo corretto e mi ricorda ancora [ClassLoader.loadClassInternal] (http://bugs.sun.com/view_bug.do?bug_id=4670071) Naturalmente si può imbrogliare in fooImpl tramite 'monitorExit' /' moniorEnter' – bestsss

+0

@bestss Anche se si scrive il proprio codice byte, è necessario che corrisponda all'ingresso/uscita del monitor. (IIRC c'è qualche margine particolare nelle specifiche, ma nessuna implementazione ragionevole.) Anche se 'fooImpl' potrebbe' aspettare'. –

20

L'errore di utilizzare sincronizzato quando si esegue l'override di un metodo sincronizzato ha il potenziale per provocare errori di runtime. A titolo di salvaguardia, c'è un controllore Eclipse che puoi attivare per rilevare questa condizione. L'impostazione predefinita è "ignora". "Attenzione" è anche una scelta valida. preferences

che produrrà questo messaggio:

enter image description here

enter image description here

+3

+1 Buono a sapersi! –