2010-06-28 3 views
6

Ich weiß, wenn Sie Methode nur von einem Thread ausgeführt werden möchten, die Sie mit synchronized Schlüsselwort zu deklarieren.Wie sperrt man eine Methode für eine ganze Klasse mit synchronisierten?

Was ist mit Klassen, wie eine Sperre für eine ganze Klasse von Objekten bereitzustellen, wenn ein Thread Code auf einer Instanz dieser Klasse ausführt?

Mit anderen Worten, wenn ein Thread eine Methode für ein Objekt ausführt, sollte kein anderer Thread zulässig sein, um dieselbe Methode auch für eine andere Instanz derselben Klasse auszuführen.

+1

Können Sie erklären, warum Sie dies tun müssen? Ich habe das Gefühl, dass du das falsche Problem angreifst. Das Synchronisieren von Methodenaufrufen über * völlig unterschiedliche Instanzen Ihrer Klasse * klingt wie das eigentliche Problem woanders. –

Antwort

8

Sie synchronisieren zu einem bestimmten Objekt, entweder einige bezeichneten statischen Sperrobjekt oder das Klassenobjekt (was geschieht, wenn statische Methoden deklariert sind synchronisiert werden):

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 
     } 
    } 
} 

Jede Variante hat seine eigenen Vor- und Nachteile ; Durch das Sperren der Klasse kann anderer Code außerhalb der Klasse die gleiche Sperre für seine eigenen Gründe verwenden (wodurch er eine höhere Synchronisierung als die von Ihnen gebotene Orchestrierung durchführen kann), während die Methode static final Object lock die Sperre durch Sperren zulässt field private (was es einfacher macht, über die Sperrung nachzudenken und zu vermeiden, dass Ihr Code blockiert wird, weil jemand anderen schlechten Code geschrieben hat).

Sie könnte natürlich auch eine gewissen Synchronisationsmechanismus von java.util.concurrent, wie expliziten Lock s verwenden, die sie über mehr Kontrolle bieten Sperren (und ReentrantLock zur Zeit führt ein wenig besser als implizite Sperren unter hohen Konkurrenz).


Edit: Beachten Sie, dass statische/global Sperren zu gehen nicht eine gute Möglichkeit, - es jede Instanz der Klasse bedeutet immer zu jedem anderen Fall im wesentlichen gebunden werden (die, beiseite geschaffen werden sie sie davon schwerer zu testen oder den Code zu lesen, kann die Skalierbarkeit ernsthaft beeinträchtigen). Ich nehme an, dass Sie das tun, um eine Art globalen Staat zu synchronisieren? In diesem Fall würde ich in Betracht ziehen, den globalen/statischen Status stattdessen in eine Klasse einzufügen und die Synchronisierung pro Instanz statt global zu implementieren.

Statt etwas wie folgt aus:

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

es wie folgt tun:

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

Jetzt foo und bar sind miteinander noch gebunden, sie können aber von frob und quux unabhängig arbeiten.

+0

Dieser (letzte) Weg ist fast sicher das Beste, was ich sagen würde. Es macht transparent, was mit Unterklassen Ihrer Klasse und mit mehreren Instanzen Ihres Programms passieren soll, und auch, was Sie beachten müssen, wenn statische Methoden benötigt werden. –

2

Sie könnten eine statische Mutex innerhalb dieser Methode verwenden. Daher blockiert jeder gleichzeitige Thread innerhalb der Methode, während ein anderer ihn ausführt, unabhängig davon, zu welchem ​​Objekt der Klasse er gehört. Ich glaube nicht, dass es ein spezielles einzelnes Keyword gibt, das denselben Effekt wie synchronized erzeugt.

Es ist eine ziemlich aggressive Synchronisation, ich würde es so weit wie möglich vermeiden.

0

Es gibt keinen eingebauten Mechanismus dafür. Erstellen Sie Ihr eigenes statisches Sperrattribut und stellen Sie sicher, dass Sie es sperren und in jeder Methode entsperren. Vergessen Sie nicht die Ausnahmen - stellen Sie sicher, dass Sie sie in den "finally" -Abschnitten entsperren.

5

Wenn Sie statische synchronisierte Methoden verwenden, werden sie über die Klassensperre gesperrt. Sie können auch ein statisches Objekt in der Klasse deklarieren und sperren, dass in einer Methode, die ich über etwas glauben, wie:

private static final Object STATIC_LOCK = new Object(); 

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

Diese Arbeit sollte:

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

Welche ‚missuses‘ die Laufzeit-Darstellung der Klasse für Verriegelung. Dies ist möglich, da jedes Objekt in Java als Mutex verwendet werden kann.

+0

Angesichts der Tatsache, dass statische synchronisierte Methoden auf dem Klassenobjekt synchronisiert werden, warum halten Sie dies für einen Missbrauch? –

+0

Ist das so? In diesem Fall, wenn die Java-Designer es so machen, ist es wahrscheinlich kein Missbrauch. Ich dachte, dass der sauberste Weg ein dediziertes statisches Monitor/Mutex-Objekt wäre, und dass die Verwendung einiger Objekte ein bisschen ein Hack ist - obwohl ich mich persönlich für diese Option entscheiden würde. Setzen Sie die Missuse jetzt in Anführungszeichen :) –

2

Synchronisieren auf statischem Feld Ihrer Klasse oder die Klasse selbst:

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

Beiden Themen diese Konstruktion

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

Diesen Ansatz profitiert von der Tatsache, verwenden müssen, dass die Klasse selbst ist ein Objekt und deshalb hat es einen Monitor. Dann brauchen Sie keine künstliche statische Instanz.

0

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

spricht über mehrere Möglichkeiten, es zu erreichen. Im Allgemeinen sind Sperren prohibitiv und behindern die Vorteile des Threading. Daher sollte der kritische Code so weit wie möglich minimiert werden.

Soll eine Klassenhebelsperre auf statische Variablen der Klasse zugreifen oder dient sie zum Schutz des Zugriffs auf eine gemeinsame externe Ressource der Klasse? In diesem Fall sollten Sie beim Zugriff darauf eine separate Sperre haben.

Verwandte Themen