2 Stimmen

Thread-Sicherheit einer fließenden Klasse mit clone() und nicht-finalen Feldern

Diese fließend wie Klasse ist nicht streng unveränderlich, weil die Felder nicht endgültig sind, aber ist es Thread sicher, und warum?

Das Problem mit der Threadsicherheit, das mich beschäftigt, ist nicht die Race Condition, sondern die Sichtbarkeit der Variablen. Ich weiß, dass es einen Workaround gibt, der finale Variablen und einen Konstruktor anstelle von clone() + Zuweisung verwendet. Ich möchte nur wissen, ob dieses Beispiel eine brauchbare Alternative ist.

public class IsItSafe implements Cloneable {

    private int foo;
    private int bar;

    public IsItSafe foo(int foo) {
        IsItSafe clone = clone();
        clone.foo = foo;
        return clone;
    }

    public IsItSafe bar(int bar) {
        IsItSafe clone = clone();
        clone.bar = bar;
        return clone;
    }

    public int getFoo() {
        return foo;
    }

    public int getBar() {
        return bar;
    }

    protected IsItSafe clone() {
        try {
            return (IsItSafe) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new Error(e);
        }
    }
}

1voto

assylias Punkte 308529

Diese Gewinde ist sich ziemlich einig, dass die Klasse aufgrund von Sichtbarkeitsproblemen nicht thread-sicher ist.

Warum sagen Sie, dass die Klasse nicht unveränderlich ist? Der Zustand der Klasse wird durch foo und bar definiert, die für bestimmte Instanzen nicht von außerhalb der Klasse geändert werden können, sobald die Instanz erstellt wurde. Sie ist also unveränderlich, auch wenn die Felder nicht explizit als final deklariert sind.

~~

An der einzigen Stelle, an der foo und bar geändert werden (in den Methoden foo() und bar()), werden die Änderungen an einer lokalen Variablen vorgenommen, auf die definitionsgemäß jeweils nur ein Thread zugreifen kann.

EDIT

Ich denke, dies ist ein Beispiel für Stack Confinement, wie es in Java Concurrency in Practice (3.3.2) definiert ist, wodurch die Methoden foo() und bar() thread-sicher werden, weil clone darf die Methode nicht verlassen, bevor sie vollständig aufgebaut ist.

~~

Lokale Variablen sind von Natur aus auf den ausführenden Thread beschränkt; sie befinden sich auf dem Stack des ausführenden Threads, der für andere Threads nicht zugänglich ist.

1voto

Joe23 Punkte 5473

Sie halten keine Sperre, während Sie das Feld setzen, und wie Sie selbst erwähnen, ist das Feld nicht endgültig.

Daher ist dieser Ansatz vom Standpunkt der Sichtbarkeit aus gesehen nicht thread-sicher.

Hier einige weitere Erläuterungen: https://stackoverflow.com/a/9633968/136247

Aktualisierung in Bezug auf die Frage der Verwendung flüchtiger Stoffe:

Um des Arguments willen wird durch die Verwendung von Volatile das Threading-Problem hier behoben.
Sie sollten jedoch endgültige Felder und einen Kopierkonstruktor noch einmal überdenken, denn:

  • Der Feldzugriff wird etwas schneller sein (die Lesevorgänge können immer aus dem Cache der CPU kommen)
  • Sie vermeiden die entmutigende Verwendung von clone (siehe Effektives Java von Josh Bloch)
  • Konstruktor mit endgültigen Feldern ist ein bekanntes Idiom für unveränderliche Klassen und wird von Lesern des Codes leicht erkannt werden
  • Felder markieren volatile während die Absicht, dass sie unveränderlich sein sollen, ein Widerspruch in sich selbst ist ;)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X