2010-06-28 10 views
6

So che quando si desidera bloccare il metodo per essere eseguito da un solo thread lo si dichiara con la parola chiave synchronized.Come bloccare un metodo per un'intera classe usando sincronizzato?

Per quanto riguarda le classi, come fornire un blocco su un'intera classe di oggetti quando un thread esegue un codice su un'istanza di tale classe?

In altre parole, quando un thread sta eseguendo un metodo su un oggetto, nessun altro thread deve essere autorizzato ad eseguire lo stesso metodo anche su un'istanza diversa della stessa classe.

+1

Puoi spiegare perché è necessario farlo? Ho la sensazione che potresti attaccare il problema sbagliato. La necessità di sincronizzare le chiamate di metodo attraverso * istanze completamente diverse della tua classe * sembra che il vero problema sia da qualche altra parte. –

risposta

8

Si sincronizza su un oggetto specifico, o qualche oggetto serratura statico designato, o l'oggetto classe (che avviene quando i metodi statici sono dichiarati essere sincronizzato):

class X { 
    private static final Object lock = new Object(); 
    public void oneAtATime() { 
     synchronized (lock) { 
      // Do stuff 
     } 
    } 
} 
class Y { 
    public void oneAtATime() { 
     synchronized (Y.class) { 
      // Do stuff 
     } 
    } 
} 

Ogni variante ha i suoi vantaggi e svantaggi ; il blocco sulla classe consente ad altri codici, al di fuori della classe, di utilizzare lo stesso blocco per i propri motivi (che consente di orchestrare più sincronizzazione di alto livello rispetto a ciò che si fornisce) mentre l'approccio static final Object lock consente di vietarlo bloccando il blocco campo privato (che rende più facile ragionare sul blocco ed evitare il codice dal deadlock perché qualcun altro ha scritto un codice errato).

Si potrebbe naturalmente anche usare un meccanismo di sincronizzazione dal java.util.concurrent, come espliciti Lock s, che forniscono maggiore controllo sulla bloccaggio (e ReentrantLock attualmente esegue un po 'meglio di serrature impliciti sotto alta contesa).


Edit: Si noti che/serrature globali statici non sono un ottimo modo per andare - significa ogni istanza della classe mai creato sarà essenzialmente essere legato a tutti gli altri casi (che, a parte che lo rende più difficile da testare o leggere il codice, può danneggiare gravemente la scalabilità). Suppongo che tu faccia questo per sincronizzare un qualche tipo di stato globale? In tal caso, prenderei in considerazione l'idea di inserire lo stato globale/statico in una classe e implementare la sincronizzazione per istanza anziché a livello globale.

Invece di qualcosa di simile a questo:

class Z { 
    private static int state; 
    public void oneAtATime(){ 
     synchronized (Z.class) { 
      state++; 
     } 
    } 
} 

fare in questo modo:

class State { 
    private int value; 
    public synchronized void mutate(){ value++; } 
} 
class Z { 
    private final State state; 
    public Z(State state){ 
     this.state = state; 
    } 
    public void oneAtATime(){ 
     state.mutate(); 
    } 
} 
// Usage: 
State s1 = new State(), s2 = new State(); 
Z foo = new Z(s1); 
Z bar = new Z(s1); 
Z frob = new Z(s2); 
Z quux = new Z(s2); 

Ora foo e bar sono ancora legati gli uni agli altri, ma possono lavorare indipendentemente da frob e quux.

+0

Questo (ultimo) modo è quasi certamente il migliore che potrei dire. Rende trasparente ciò che dovrebbe accadere con sottoclassi della tua classe, e con più istanze del tuo programma, e anche a cosa fare attenzione quando sono necessari metodi statici. –

2

È possibile utilizzare uno statico Mutex all'interno di tale metodo. Quindi qualsiasi thread concorrente sta bloccando il metodo mentre un altro lo sta eseguendo indipendentemente dall'oggetto della classe a cui appartiene. Non penso che ci sia una singola parola chiave speciale per produrre lo stesso effetto come synchronized.

È una sincronizzazione piuttosto aggressiva, eviterei il più possibile.

0

Non esiste un meccanismo integrato per questo. Crea il tuo attributo di blocco statico e assicurati di bloccarlo e sbloccarlo in tutti i modi. Non dimenticare le eccezioni: assicurati di sbloccarlo nelle sezioni "finalmente".

5

Se si utilizzano metodi sincronizzati statici, vengono bloccati tramite Blocco classe. È inoltre possibile dichiarare un oggetto statico nella classe e bloccare che in un metodo Credo via qualcosa come:

private static final Object STATIC_LOCK = new Object(); 

private void foo() { 
    synchronized (STATIC_LOCK) { 
      //do stuff... 
    } 
} 
0

Questo dovrebbe funzionare:

public class MyClass { 
    void synchronizedMethod() { 
    synchronized (MyClass.class) { 
     // synchronized on static level 
    } 
    } 
} 

Quale 'missuses' runtime-rappresentanza della classe per bloccaggio. Questo è possibile in quanto qualsiasi oggetto può essere usato come mutex in Java.

+0

Dato che i metodi sincronizzati statici si sincronizzano sull'oggetto classe, perché consideri di fare un uso improprio? –

+0

È così? In questo caso, se i progettisti Java fanno così, allora probabilmente non è un errore. Pensavo che il modo più pulito fosse di avere un oggetto Monitor/Mutex statico dedicato e che l'utilizzo di qualche oggetto fosse un po 'un trucco, anche se personalmente avrei optato personalmente per quell'opzione. Metti subito il missus tra virgolette :) –

2

Sincronizza campo statico della classe, o la classe stessa:

synchronized(MyClass.class) { 
     // mutually excluded method body 
} 
1

Entrambe le discussioni devono utilizzare questa costruzione

public void someMethod() { 
    synchronized(ClassThatShouldBeProtected.class) { 
    someSynchronizedCode(); 
    } 
} 

benefici di questo approccio dal fatto, che la classe stessa è un oggetto e quindi ha un monitor. Quindi non hai bisogno di istanze statiche artificiali.

0

http://www.janeg.ca/scjp/threads/synchronization.html

parla di diversi modi per realizzarla. in generale, i blocchi sono proibitivi e ostacolano i vantaggi della filettatura. quindi il codice critico dovrebbe essere minimizzato il più possibile.

si desidera un blocco della leva di classe per accedere a variabili statiche della classe o per proteggere l'accesso a una risorsa esterna comune della classe? in tal caso dovresti avere un blocco separato mentre accederai.

Problemi correlati