2012-09-06 2 views
12

Making Unter:eine Klasse Thread-sichere

public class TestSeven extends Thread { 

private static int x; 

public synchronized void doThings() { 
    int current = x; 
    current++; 
    x = current; 
} 

public void run() { 
    doThings(); 
    } 
} 

Welche Aussage ist wahr?

A. Kompilierung schlägt fehl.

B. Eine Ausnahme wird zur Laufzeit ausgelöst.

C. Das Synchronisieren der run() - Methode würde die Klasse threadsicher machen.

D. Die Daten in der Variablen "x" sind vor gleichzeitigen Zugriffsproblemen geschützt.

E. Das Deklarieren der doThings() - Methode als statisch würde die Klasse threadsicher machen.

F. Das Wrappen der Anweisungen in doThings() in einem synchronisierten Block (new Object()) {} würde die Klasse threadsicher machen.

ist es nicht genug, doThings() als synchronisiert zu markieren, um diese Klasse Thread-sicher zu machen? Ich sehe, dass die richtige Antwort D ist, aber die Modellantwort dieser Frage ist E, aber ich verstehe nicht warum?

Antwort

17

E. Die Deklaration der doThings() - Methode als statisch würde die Klasse threadsicher machen.

Das ist eine knifflige Antwort. Die Methode ist bereits synchronisiert, aber auf der Instanz, während der Zustand in einem statischen Feld ist, d.h. auf der Klasse. Making it static synchronized ist in der Tat die richtige Antwort, denn dann synchronisiert es auf der Klasse, nicht auf einer (bedeutungslosen) Instanz.

D. Die Daten in der Variablen "x" sind vor gleichzeitigen Zugriffsproblemen geschützt.

private static int x; 

Dies ist eine statische Variable. Es wird von allen Instanzen der Klasse gemeinsam genutzt, so dass die Synchronisierung auf einzelnen Instanzen nicht hilfreich ist, genauso wie F nicht hilfreich wäre, da es auf einem vollständigen Wegwerf-Dummy-Objekt synchronisiert wird.

11

Nach der language spec:

Eine synchronisierte Methode erhält einen Monitor (§17.1), bevor sie ausgeführt wird.

Bei einer (statischen) Klassenmethode wird der Monitor verwendet, der dem Klassenobjekt für die Klassen der Methode zugeordnet ist.

Bei einer Instanzmethode wird der zugehörige Monitor (das Objekt , für das die Methode aufgerufen wurde) verwendet.

Das bedeutet, dass in dem Code versehen die synchronized Schlüsselwort, das Verfahren führt zu einer Sperre auf this vor der Ausführung des Körpers des Verfahrens zu erfassen. Da x jedoch static ist, wird nicht sichergestellt, dass das Update auf x atomar erfolgt. (Eine andere Instanz der Klasse könnte in die synchronisierte Region eintreten und gleichzeitig eine Aktualisierung vornehmen, da sie unterschiedliche Werte und damit unterschiedliche Sperren haben.)

Wenn Sie jedoch doStuff statisch deklarieren, werden alle Aufrufe der Methode die gleiche Sperre erhalten (die auf der Class) und somit den gegenseitigen Ausschluss im Methodenkörper sicherstellen.

die Vorgaben Rechtschreibung wirklich darauf hin, dass:

class A { 
    static synchronized void doSomething() { 
     // ... 
    } 
} 

ist buchstäblich dasselbe wie

class A { 
    static void doSomething() { 
     synchronized(A.class) { 
      // ... 
     } 
    } 
} 

ähnlich:

class B { 
    synchronized void doSomething() { 
     // ... 
    } 
} 

ist buchstäblich dasselbe wie

class B { 
    void doSomething() { 
     synchronized (this) { 
      // ... 
     } 
    } 
} 
6

Durch die Synchronisation der doThings() - Methode halten Sie die Sperre für ein bestimmtes TestSeven-Objekt fest. Statische Variablen der Klasse gehören jedoch nicht zu der spezifischen Instanz des Objekts. Sie gehören zum Klassenobjekt TestSeven.class. Also, entweder konnte man für ein

synchronized (TestSeven.class){ 
    int current = x; 
    current++; 
    x = current; 
} 

in Ihrem doThings gehen() -Methode, die die Klassensperre innerhalb einer Instanz Sperre erwerben, die Dinge zu übertreiben. Sie können also die Methode als statisch markieren, sodass Sie am Ende nur die Sperre des Klassenobjekts erhalten.

-6

Ich stimme mit Ihnen überein, dass die richtige Antwort D. ist. Ich würde sagen, E ist falsch, wenn ich doThings() als statisch festlegen und das synchronisierte Schlüsselwort entfernen, könnte ich nur 50 TestSeven Threads starten und es könnte resultieren in falschem x-Wert.

Hinweis: Ich lag hier falsch, ich habe den Punkt verpasst, dass die synchronisierte Methode ohne statische tatsächlich die Instanz als den Sperrmonitor anstelle der Klasse selbst verwenden.

+3

D ist nicht korrekt. – Keppil

+1

E ist korrekt, weil es nicht heißt "entferne das synchronisierte Schlüsselwort". Unnötig knifflige Phrasierung, aber genau das bekommen Sie bei diesen Prüfungen. – Thilo

+0

D ist korrekt, da es bei der gegebenen Klasse keine andere Möglichkeit gibt, den Wert von x zu ändern. Wenn das Hinzufügen einer anderen Methode erlaubt ist, würde ich sagen, dass auch die Lösung E nicht korrekt ist. –

1

Da x ist static andere Threads könnte es zur gleichen Zeit ändern doThings Methode läuft. Making doThingsstatic wird dies zu stoppen.