Frage

In Java Zuordnung ist atomar, wenn die Größe der Variable kleiner oder auf 32 Bits gleich, aber nicht, wenn mehr als 32 Bit.

Was (volatile / synchronisiert) würde effizienter sein bei Doppel- oder langer Zuordnung zu benutzen?

Wie,

  volatile double x = y;

synchronisiert ist nicht anwendbar mit primitivem Argumente. Wie kann ich in diesem Fall synchronisiert benutzen? Natürlich möchte ich nicht meine Klasse sperren, so this sollte nicht verwendet werden.

War es hilfreich?

Lösung

Wenn Sie auf dem Objekt finden Verriegelung selbst zu schwer, dann synchronisiert ist der Weg zu gehen. Vor Java 1.5 volatilem kann eine gute Wahl gewesen, aber jetzt flüchtig einen sehr großen Einfluss durch Erzwingen Anweisung Ordnung auf dem Verfahren haben kann, wo die Zuordnung geschieht. Erstellen Sie ein separates Objekt (private final Object X_LOCK = new Object();) und synchronisieren auf sie bei der Einstellung oder den Wert dieser Doppel bekommen. Dies wird Ihnen ein feines Maß an Kontrolle über die Verriegelung, die es scheint, dass Sie benötigen.

In dem neuen Concurrency-Paket gibt es mehr Optionen, wie AtomicReference, die einen guten Ersatz für flüchtig sein können, wenn Sie wirklich zu vermeiden Synchronisation benötigen.

Andere Tipps

Was wollen Sie tun? Die synchronized und volatile Schlüsselwörter sind Mechanismen in Java, die verwendet werden können, um sicherzustellen, dass konsistente Werte von verschiedenen Threads beobachtet werden, um die gleichen Daten zu lesen. Insbesondere ermöglichen sie Ihnen Grund zu passiert-vor Beziehungen in Ihren Programmen.

richtig Zugriff nicht-volatile Felder über einen Link synchronized oder final, um in einem Multi-Threaded-Programm

Sie können einfach nicht vermeiden. Das heißt, die Hauptgrund, dass Sie wahrscheinlich benötigen synchronized über volatile sind, ist die Voraussetzung für den Einsatz atomarer Vergleichen und Satz Operationen (d es wird keine Leistung Berücksichtigung sein). Zum Beispiel in einem Multi-Threaded-Programm:

volatile int i = 0;

public void foo() { 
    if (i == 0) i = i + 1;
}

Der obige Code ist von Natur aus unsicher, obwohl die Erklärung der Variable als flüchtige Mittel sein, die Lese- und Schreibvorgänge in den Hauptspeicher geleert werden - die einzige sichere Durchführung solcher Verfahren würde wie etwas sein:

int i = 0;

public synchronized void foo() {
    if (i == 0) i = i + 1;
}

So welche sollten Sie bevorzugen? Nun, wenn Sie mehrere Threads haben ein Feld davon abhängig Feldwert zu modifizieren (d Vergleichs- und Satz), dann synchronized ist die einzige sichere Lösung.

Es lohnt sich auch sagen: die Performance-Overhead von synchronized ist kein Problem, (in der überwiegenden Mehrheit der Fälle). Synchronization-Performance-Probleme sind in der Regel durch unnötige Code Engpässe, Deadlocks oder Livelocks und können bei Bedarf abgeschwächt werden. Alle reine Taktzyklen Overhead wird durch andere Dinge den Schatten gestellt werden Sie Anwendung tut. Datei IO, Datenbankabfragen, etc remoting

flüchtig ist sicherlich der Weg zu gehen, wenn Sie nur einen Auftrag zu tun. Ich bin sicher, Sie wissen, aber da es erzogen wurde: Wenn Sie komplexere Operationen tun möchte (der Wert zum Beispiel erhöhen) Sie würde syncrhonize benötigen. i ++ ist Thread nie sicher für jede Art von Variablen. Sie müssen Synch. i ++ und dergleichen, da das ist eigentlich mehr als 1 Betrieb.

Nicht: Es wurde zum Ausdruck gebracht, dass man AtomicDouble verwenden könnte, aber es gibt derzeit keine AtomicDouble in java.util.concurrent.atomic

Wenn Sie eine mehr Operationen auf x tun, die es auf einen neuen Wert am Ende erfordert Einstellung ist es möglich, diese sichere Art und Weise in einem Thread ohne Verriegelung zu tun, was auch immer, und hat es Thread-sicher sein, Verwendung vergleichen und eingestellt. Beispiel:

AtomicLong x = new AtomicLong(SomeValue);
public void doStuff() {
  double oldX;
  double newX;
  do {
    oldX = x.get();
    newX = calculateNewX(oldX);
  } while (!x.compareAndSet
      (Double.doubleToLongBits(oldX), Double.doubleToLongBits(newX)));

Das funktioniert, weil compareAndSet werden sehen, ob der Wert von x seit dem letzten Mal geändert hat Sie es lesen. Wenn x geändert hat, dann sind Sie gezwungen, die Berechnung immer wieder zu tun und wieder versuchen, es zu setzen.

Sie können natürlich Ihre eigenen AtomicDouble implementieren, anstatt diese doubleToLongBits Umwandlungen zu tun. Werfen Sie einen Blick auf AtomicFieldUpdater.

KDSRathore, können Sie einige expliziten Sperren verwenden, oder ein Dummy-Object-Objekt machen = new Object (), auf die Sie eine Synchronisierung in Setter / Getter dieses Doppel

Nach der Oracle-Dokumentation , können Sie verwenden, um flüchtige Doppel Objekt zu verweisen:

volatile Double x = y;

"Schreibt und liest von Referenzen sind immer atomar, unabhängig davon, ob sie durchgeführt werden als 32-Bit oder 64-Bit-Werte."

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top