Ist das technisch sicher, obwohl es veränderbar ist?

8

Ja, die private Mitgliedsvariable bar sollte final richtig sein? Aber in diesem Fall ist es eine atomare Operation, einfach den Wert von int zu lesen. Ist das also technisch sicher?

%Vor%

// nehme an, dass unendlich viele Threads wiederholt getBar für dieselbe Instanz von Foo aufrufen.

BEARBEITEN:

Angenommen, dies ist der gesamte Code für die Klasse Foo ; Alle Threads mit einem Verweis auf eine Foo -Instanz können den Wert von bar nicht ändern (ohne dabei auf Längen wie Reflektion usw. zu setzen).

    
Finbarr 05.05.2010, 07:46
quelle

1 Antwort

7

Letzte Aktualisierung: Meine erste Schlussfolgerung war zufällig, nur meine Argumentation war fehlerhaft :-( Ich habe meine Antwort überarbeitet, um sie einigermaßen kohärent zu machen, um die Spuren meiner früheren nicht zu verbergen Schnitzer.

Fazit

Wie @Wyzard sagte, obwohl bar nach der Konstruktion nicht geändert werden kann, ist Foo immer noch nicht Thread-sicher. Das Problem ist nicht Atomizität, sondern Sichtbarkeit. Wenn Thread 1 den Wert von bar im Konstruktor ändert (von seinem Standardwert 0), gibt es keine Garantie, wenn andere Threads den neuen Wert sehen (oder ob sie überhaupt sehen ).

So foo sieht wie ein unveränderliches Objekt aus. Zitat aus Java Concurrency in Practice , Abschnitt 3.4:

  

Ein Objekt ist unveränderlich, wenn:

     
  • Sein Zustand kann nach der Konstruktion nicht geändert werden;
  •   
  • Alle seine Felder sind endgültig; und
  •   
  • Es ist richtig konstruiert (die Referenz verschwindet nicht während der Konstruktion).
  •   

Foo sieht auf 1) und 3) OK aus, aber nicht 2). Und das ist ein entscheidender Punkt, aufgrund der obigen Überlegungen. Das Deklarieren einer Variablen final ist eine Möglichkeit, die Sichtbarkeit zwischen verschiedenen Threads sicherzustellen. Die anderen Mittel deklarieren bar volatile oder synchronisieren ihre Zugriffsmethode (n). Aber natürlich würde im Falle eines unveränderlichen Objekts keiner von beiden viel Sinn ergeben.

Letzte Felder

Warum garantieren final Felder Sichtbarkeit? Antwort von Java Concurrency in Practice, Abschnitt 3.5.2:

  

Da unveränderliche Objekte so wichtig sind, bietet das JavaMemory-Modell eine besondere Garantie für die Initialisierungssicherheit für die gemeinsame Nutzung unveränderlicher Objekte. Wie wir gesehen haben, bedeutet das, dass eine Objektreferenz für einen anderen Thread sichtbar wird, bedeutet nicht notwendigerweise, dass der Status dieses Objekts für den konsumierenden Thread sichtbar ist. Um eine konsistente Sicht auf den Zustand des Objekts zu gewährleisten, ist eine Synchronisation erforderlich.

     

Unveränderbare Objekte andererseits können auch dann sicher abgerufen werden, wenn keine Synchronisation zum Veröffentlichen der Objektreferenz verwendet wird. Damit diese Garantie für die Sicherheit der Initialisierung gewährleistet ist, müssen alle Anforderungen an die Unveränderlichkeit erfüllt sein: unmodifizierbarer Zustand, alle Felder sind endgültig und die richtige Konstruktion. [...]

     

Unveränderbare Objekte können von jedem Thread ohne zusätzliche Synchronisierung sicher verwendet werden, selbst wenn keine Synchronisierung für deren Veröffentlichung verwendet wird.

     

Diese Garantie erstreckt sich auf die Werte aller letzten Felder richtig konstruierter Objekte; auf die letzten Felder kann ohne zusätzliche Synchronisation sicher zugegriffen werden. Wenn finale Felder jedoch auf veränderbare Objekte verweisen, ist weiterhin eine Synchronisierung erforderlich, um auf den Status der Objekte, auf die sie verweisen, zuzugreifen.

Und was passiert, wenn das Feld nicht final ist? Andere Threads können einen veralteten Wert des Felds automatisch anzeigen. Es gibt keine Ausnahme oder irgendeine Art von Warnung - das ist ein Grund, warum diese Art von Fehlern so schwer zu verfolgen ist.

    
Péter Török 05.05.2010, 07:48
quelle

Tags und Links