Dieses Blog durchsuchen

Freitag, 4. Oktober 2013

Multi-Thread Programmierung: Einfache Regeln

Die Multi-Thread Programmierung ist nicht einfach. Fehlerhafter Code kann in sogenannten "Race Conditions" münden. Dies sind Fehler, die aufgrund von konkurrierendem Zugriff von Threads auf gemeinsam genutzte Ressourcen entstehen. Race Conditions sind deshalb schwer zu erkennen, da sie nicht reproduzierbar, sondern meist nur unter hoher Last (also im produktiven Betrieb) auftreten. Alle Unit-Tests sind grün, die Anwender haben stundenlang getestet und dann treten in Produktion massenweise, unvorhergesehene Fehler auf. Keine schöne Situation.

Die Materie der Multi-Thread Programmierung ist schwierig und umfangreich. Wer Software entwickelt, die von vielen Threads parallel durchlaufen wird, sollte sich unbedingt damit auseinandersetzen. Gerade in Zeiten von Prozessoren mit vielen Kernen wäre es eine Verschwendung von Prozessor-Ressourcen den Code vor Nebenläufigkeit abzuschirmen.

Aber auch beim Einsetzen von Frameworks und insbesondere auch in der JavaEE Entwicklung sollte man sich der o. g. Problematik stets bewusst sein. Zwar nehmen einem Application-Server viel Arbeit ab, aber man sollte trotzdem wissen, wie diese funktionieren und worauf zu achten ist. Der Tomcat z. B. (sowie auch der JBoss) verwenden Servlets, um (HTTP-)Requests abzuarbeiten. Diese Servlets werden u. U. von vielen Threads parallel durchlaufen, sodass es hier durchaus zu Multi-Thread Fehlern kommen kann.

Um die gröbsten Fehler zu vermeiden, folgen drei Tipps. Wenn diese beachtet werden, ist die Software im Hinblick auf Thread-Sicherheit schon auf einem guten Weg!

  • Wenn möglich auf Instanz-Variablen verzichten
Variablen, die lokal im Scope einer Methode definiert werden, können niemals zu Race Conditions führen, da sie nicht zwischen Threads geteilt werden.

  • Möglichst auf statische Klassenvariablen verzichten
Diese sind besonders gefährlich, da sie potenziell (je nach Sichtbarkeit) in der kompletten Anwendung und nur ein einziges Mal vorkommen und von allen Threads geteilt werden.
  • Falls Variablen geteilt werden müssen, diese mit synchronized schützen
Eine (Instanz-)Variable, die zwischen verschiedenen Threads geteilt werden soll, sollte mit Hilfe des Schlüsselworts synchronized geschützt werden. Dies bedeutet, dass jeweils nur ein Thread die Variable lesen bzw. schreiben kann. Wichtig: Unbedingt sowohl das Schreiben als auch das Lesen synchronisieren! Dies erfolgt üblicherweise über das Versehen der getter und setter Methode mit dem  Schlüsselwort synchronized.

Schließlich sollte man sich auch immer darüber informieren, ob die verwendeten APIs Thread-sicher sind. Heißer Kandidat sind Connection-Objekte, die applikationsweit wiederverwendet werden. Lassen sich hierüber keine Informatinen finden, sollten diese Objekte sicherheitshalber auch synchronisiert werden.

2 Kommentare: