2016-08-07 41 views
1

Ein abstrakter/Ausschnitt aus Java Concurrency In Praxis-Wie verhindert das Erstellen eines Felds als final für ein Objekt, dass ein Thread eine Nullreferenz für dasselbe Objekt erkennt?

// Unsafe publication 
public Holder holder; 

public void initialize(){ 
    holder = new holder(42); 
} 

Zwei Dinge können mit unsachgemäß veröffentlichten Objekten schief gehen. Andere Threads könnten einen veralteten Wert für das Halterfeld sehen und somit einen null Referenzwert oder einen anderen älteren Wert sehen, obwohl ein Wert im Halter platziert wurde. Aber viel schlimmer, andere Threads konnten einen up-to-date Wert für die Halterreferenz sehen, aber veraltete Werte für den Zustand der Halter. Um die Dinge noch weniger vorhersehbar zu machen, kann ein Thread einen veralteten Wert sehen, wenn er das erste Mal ein Feld liest, und dann ein aktuelleres Wert das nächste Mal, was ist, warum assertSanity AssertionError werfen kann.

auch Objektverweis auf einem anderen Thread sichtbar wird, bedeutet nicht notwendigerweise, dass der Zustand des Objekts an den konsumierende Faden sichtbar ist

public class Holder{ 
    private int n; 

    public Holder(int n) { 
     this.n = n; 
    } 

    public void assertSanity(){ 
     if (n != n) 
      throw new AssertionError("This statement is false."); 
    } 
} 

Ofcouse, eine der Möglichkeiten, zu beheben, es wäre zu tun/machen

public volatile Holder holder; 

Der Autor schlägt vor, eine andere approach-

Wenn Halter unveränderlich waren, konnte assertSanity nicht AssertionError werfen, auch wenn der Halter nicht ordnungsgemäß veröffentlicht wurde.)

public class Holder{ 
     private final int n; 
//... 
} 

Aber wie? Die unsichere Veröffentlichung ist immer noch da. Ich denke es ist immer noch möglich für einen Thread eine Null Referenz auf Halter zu bekommen. Bitte vorschlagen.

+0

In Verbindung stehende http://StackOverflow.com/Questions/16107683/improper-Publication-of-JavaObjectReference und http://StackOverflow.com/A/6088679/1743880 – Tunaki

Antwort

1

Die JLS beschreibt die speziellen Semantik der endgültigen Felder

https://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.5

letzte Felder auch Programmierer erlauben Thread-sichere unveränderliche Objekte ohne Synchronisation zu implementieren. Ein threadsicheres unveränderliches Objekt wird von allen Threads als unveränderbar angesehen, selbst wenn eine Datenrasse verwendet wird, um Verweise auf das unveränderliche Objekt zwischen Threads zu übergeben. [...]. Die letzten Felder müssen korrekt verwendet werden, um eine Unveränderbarkeit zu gewährleisten.

Aber ich schlage vor, Sie das ganze Kapitel lesen 17.5

„müssen korrekt verwendet werden“ bezieht sich auf Konstruktor tatsächlich beendet ist (und war this nicht entgangen) und nicht mit Reflexion Hantieren.

aus http://www.angelikalanger.com/Articles/EffectiveJava/38.JMM-Overview/38.JMM-Overview.html übersetzt, die ist:

Das Ende des Konstruktors eine Teilspülung verursacht, alle endgültigen Variablen und abhängigen Objekte in den Speicher zu schreiben. [...]. Der erste Lesezugriff einer endgültigen Variablen bewirkt eine teilweise Aktualisierung, wobei die endgültigen Variablen und abhängigen Objekte aus dem Speicher geladen werden. Eine andere Bezugnahme tritt nicht auf [...].