Was ist das häufigste Parallelitätsproblem, auf das Sie in Java gestoßen sind? [closed]

Lesezeit: 7 Minuten

Dies ist eine Art Umfrage zu häufigen Nebenläufigkeitsproblemen in Java. Ein Beispiel könnte der klassische Deadlock oder die Race-Condition oder vielleicht EDT-Threading-Bugs in Swing sein. Ich interessiere mich sowohl für eine Breite möglicher Probleme als auch dafür, welche Probleme am häufigsten auftreten. Hinterlassen Sie also bitte eine spezifische Antwort auf einen Java-Parallelitätsfehler pro Kommentar und stimmen Sie ab, wenn Sie einen sehen, auf den Sie gestoßen sind.

  • Warum ist das geschlossen? Dies ist sowohl für andere Programmierer nützlich, die um Parallelität in Java bitten, als auch um eine Vorstellung davon zu bekommen, welche Klassen von Parallelitätsfehlern von anderen Java-Entwicklern am häufigsten beobachtet werden.

    – L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳

    31. März 2013 um 1:56 Uhr

  • @Longpoke Die Abschlussnachricht erklärt, warum sie geschlossen ist. Dies ist keine Frage mit einer bestimmten “richtigen” Antwort, sondern eher eine Umfrage / Listenfrage. Und Stack Overflow hat nicht die Absicht, diese Art von Fragen zu hosten. Wenn Sie mit dieser Richtlinie nicht einverstanden sind, möchten Sie sie vielleicht auf Meta diskutieren.

    – Andrzej Doyle

    28. Mai 2013 um 10:56 Uhr

  • Ich denke, die Community ist anderer Meinung, da dieser Artikel mehr als 100 Aufrufe pro Tag erhält! Ich fand es sehr nützlich, da ich an der Entwicklung eines statischen Analysetools beteiligt bin, das speziell zur Behebung von Nebenläufigkeitsproblemen entwickelt wurde contemplateltd.com/threadsafe. Eine Bank mit häufig auftretenden Parallelitätsproblemen zu haben, war großartig, um ThreadSafe zu testen und zu verbessern.

    – Craig Manson

    4. März 2014 um 16:35 Uhr


  • Code-Review-Checkliste für Java Concurrency verdaut die meisten der in den Antworten auf diese Frage erwähnten Fallstricke in einer Form, die für tägliche Codeüberprüfungen geeignet ist.

    – leventow

    1. September 2019 um 16:28 Uhr

Das häufigste Parallelitätsproblem, das ich gesehen habe, ist nicht zu erkennen, dass ein Feld von einem Thread geschrieben wird nicht garantiert von einem anderen Thread zu sehen. Eine gängige Anwendung davon:

class MyThread extends Thread {
  private boolean stop = false;

  public void run() {
    while(!stop) {
      doSomeWork();
    }
  }

  public void setStop() {
    this.stop = true;
  }
}

So lange halt nicht flüchtig oder setStop und run sind nicht synchronisiert das funktioniert garantiert nicht. Dieser Fehler ist besonders teuflisch, da er zu 99,999 % in der Praxis keine Rolle spielt, da der Leser-Thread die Änderung irgendwann sehen wird – aber wir wissen nicht, wie schnell er es gesehen hat.

  • Eine großartige Lösung hierfür besteht darin, die Stop-Instanzvariable zu einem AtomicBoolean zu machen. Es löst alle Probleme der nicht flüchtigen Komponenten und schützt Sie gleichzeitig vor JMM-Problemen.

    – Kirk Wylie

    20. Januar 2009 um 23:59 Uhr

  • Es ist schlimmer als „für einige Minuten“ – Sie werden es vielleicht NIE sehen. Unter dem Speichermodell darf die JVM while(!stop) in while(true) optimieren, und dann werden Sie abgespritzt. Dies kann nur auf einigen VMs passieren, nur im Servermodus, nur wenn die JVM nach x Wiederholungen der Schleife neu kompiliert usw. Autsch!

    – Cowan

    11. Februar 2009 um 6:15 Uhr

  • Warum sollten Sie AtomicBoolean über volatile boolean verwenden? Ich entwickle für Version 1.4+, gibt es also irgendwelche Fallstricke, wenn ich nur flüchtig deklariere?

    – Schwimmbad

    29. März 2009 um 23:26 Uhr

  • Nick, ich denke, das liegt daran, dass Atomic CAS normalerweise sogar schneller ist als Volatilität. Wenn Sie für 1.4 entwickeln, besteht Ihre einzige sichere Option meiner Meinung nach darin, synchronisiert zu verwenden, da flüchtig in 1.4 nicht die Garantien für starke Speicherbarrieren wie in Java 5 hat.

    – Kuzi

    5. April 2009 um 13:04 Uhr

  • @Thomas: Das liegt am Java-Speichermodell. Sie sollten darüber lesen, wenn Sie es im Detail wissen wollen (Java Concurrency in Practice von Brian Goetz erklärt es zB gut). Kurz gesagt: Wenn Sie keine Schlüsselwörter/Konstrukte zur Speichersynchronisierung verwenden (wie volatile, synchronisiert, AtomicXyz, aber auch wenn ein Thread beendet ist), hat ein Thread KEINE Garantie dafür, die Änderungen zu sehen, die an einem Feld vorgenommen wurden, das von einem anderen Thread vorgenommen wurde

    – Kuzi

    24. August 2010 um 14:03 Uhr

  • Dafür gibt es eine IDEA-Inspektion mit dem Namen “Synchronisation auf nicht endgültigem Feld, das wahrscheinlich keine nützliche Semantik hat”. Sehr schön.

    – Jens S.

    20. Januar 2009 um 16:28 Uhr

  • Ha … das ist jetzt eine gequälte Beschreibung. “hat wahrscheinlich keine nützliche Semantik” könnte besser als “höchstwahrscheinlich defekt” beschrieben werden. 🙂

    – Alex Müller

    20. Januar 2009 um 16:45 Uhr

  • Ich denke, es war Bitter Java, das dies in seinem ReadWriteLock hatte. Glücklicherweise haben wir jetzt java.util.concurrency.locks und Doug ist ein bisschen mehr am Ball.

    – Tom Hawtin – Angelleine

    20. Januar 2009 um 16:55 Uhr

  • Ich habe dieses Problem auch oft gesehen. Nur auf endgültigen Objekten synchronisieren. FindBugset al. helfen, ja.

    – gimp

    23. Januar 2009 um 15:20 Uhr

  • ist das nur ein problem während der aufgabe? (siehe das Beispiel von @Alex Miller unten mit einer Karte) Würde dieses Kartenbeispiel auch dasselbe Problem haben?

    – Alex Beardsley

    26. Januar 2009 um 14:07 Uhr

Ein häufiges Problem ist die Verwendung von Klassen wie Calendar und SimpleDateFormat aus mehreren Threads (häufig durch Zwischenspeichern in einer statischen Variablen) ohne Synchronisierung. Diese Klassen sind nicht Thread-sicher, sodass der Multithread-Zugriff letztendlich zu seltsamen Problemen mit inkonsistentem Zustand führen wird.

  • Kennen Sie ein Open-Source-Projekt, das diesen Fehler in einer Version davon enthält? Ich suche nach konkreten Beispielen für diesen Fehler in realer Software.

    – Umprogrammierer

    7. September 2010 um 15:44 Uhr

Nicht richtig synchronisieren auf von zurückgegebenen Gegenständen Collections.synchronizedXXX()insbesondere während der Iteration oder mehrerer Operationen:

Map<String, String> map = Collections.synchronizedMap(new HashMap<String, String>());

...

if(!map.containsKey("foo"))
    map.put("foo", "bar");

Das ist falsch. Trotz Einzeloperationen synchronizedKartenzustand zwischen dem Aufrufen contains und put kann durch einen anderen Thread geändert werden. Es sollte sein:

synchronized(map) {
    if(!map.containsKey("foo"))
        map.put("foo", "bar");
}

Oder mit einem ConcurrentMap Implementierung:

map.putIfAbsent("foo", "bar");

  • Kennen Sie ein Open-Source-Projekt, das diesen Fehler in einer Version davon enthält? Ich suche nach konkreten Beispielen für diesen Fehler in realer Software.

    – Umprogrammierer

    7. September 2010 um 15:44 Uhr

Doppelt geprüfte Verriegelung. Im Großen und Ganzen.

Das Paradigma, dessen Probleme ich zu lernen begann, als ich bei BEA arbeitete, ist, dass die Leute einen Singleton auf folgende Weise überprüfen:

public Class MySingleton {
  private static MySingleton s_instance;
  public static MySingleton getInstance() {
    if(s_instance == null) {
      synchronized(MySingleton.class) { s_instance = new MySingleton(); }
    }
    return s_instance;
  }
}

Dies funktioniert nie, da möglicherweise ein anderer Thread in den synchronisierten Block gelangt ist und s_instance nicht mehr null ist. Die natürliche Änderung besteht also darin, es zu machen:

  public static MySingleton getInstance() {
    if(s_instance == null) {
      synchronized(MySingleton.class) {
        if(s_instance == null) s_instance = new MySingleton();
      }
    }
    return s_instance;
  }

Das funktioniert auch nicht, weil das Java Memory Model es nicht unterstützt. Sie müssen s_instance als flüchtig deklarieren, damit es funktioniert, und selbst dann funktioniert es nur unter Java 5.

Leute, die mit den Feinheiten des Java-Speichermodells nicht vertraut sind, bringen das durcheinander die ganze Zeit.

  • Das Enum-Singleton-Muster löst all diese Probleme (siehe Josh Blochs Kommentare dazu). Das Wissen um seine Existenz sollte unter Java-Programmierern weiter verbreitet werden.

    – Robin

    21. Januar 2009 um 8:59 Uhr

  • Mir ist noch kein einziger Fall begegnet, in dem die verzögerte Initialisierung eines Singletons tatsächlich angemessen war. Und wenn ja, deklarieren Sie einfach die Methode für synchronisiert.

    – Dov Wassermann

    29. Januar 2009 um 18:32 Uhr

  • Dies ist, was ich für die Lazy-Initialisierung von Singleton-Klassen verwende. Auch keine Synchronisation erforderlich, da diese von Java implizit gewährleistet wird. Klasse Foo { statischer Klassenhalter { statischer Foo foo = new Foo (); } statisches Foo getInstance() { return Holder.foo; } }

    – Irfan Zulfikar

    27. März 2009 um 11:17 Uhr

  • Irfan, das nennt man Pughs Methode, soweit ich mich erinnere

    – Chris R

    28. Mai 2009 um 20:52 Uhr

  • @Robin, ist es nicht einfacher, nur einen statischen Initialisierer zu verwenden? Diese laufen garantiert immer synchron.

    – matt b

    12. Juni 2009 um 18:54 Uhr

1352530cookie-checkWas ist das häufigste Parallelitätsproblem, auf das Sie in Java gestoßen sind? [closed]

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy