Parallelität, BlockingQueues (Java 7) – 1

„Hallo, Amigo!“

„Hallo, Kim!“

„Heute werde ich Ihnen etwas über Parallelität erzählen.“

Concurrency ist eine Java-Klassenbibliothek, die spezielle Klassen enthält, die für die Arbeit aus mehreren Threads optimiert wurden. Das ist ein sehr interessantes und umfangreiches Thema. Aber heute bekommen wir nur eine Einführung. Das Paket heißt java.util. Concurrent-Paket. Ich erzähle Ihnen von ein paar interessanten Klassen.

Atomtypen.

„Sie wissen bereits, dass selbst count++ keine threadsichere Operation ist. Wenn eine Variable um 1 erhöht wird, finden tatsächlich drei Operationen statt. Daher kann es zu einem Konflikt kommen, wenn die Variable geändert wird.“

„Ja, Ellie hat es mir vor nicht allzu langer Zeit gesagt:“

Thread 1 Thread 2 Ergebnis
register1 = count;
register1++;
count = register1;
register2 = count;
register2++;
count = register2;
register1 = count;
register2 = count;
register2++;
count = register2;
register1++;
count = register1;

„Genau. Dann fügte Java Datentypen hinzu, um diese Operationen als eine Einheit, also atomar (ein Atom ist unteilbar), auszuführen.“

„Zum Beispiel hat Java AtomicInteger, AtomicBoolean, AtomicDouble usw.“

„Angenommen, wir müssen eine „Gegen“-Klasse erstellen:“

Beispiel
class Counter
{
 private int c = 0;

 public void increment()
 {
  c++;
 }

 public void decrement()
 {
  c--;
 }

 public int value()
 {
  return c;
 }
}

„Wie würden Sie Objekte dieser Klasse threadsicher machen?“

„Nun, ich würde alle Methoden synchronisieren und wäre damit fertig:“

Beispiel
class synchronized Counter
{
 private int c = 0;

 public synchronized void increment()
 {
  c++;
 }

 public synchronized void decrement()
 {
  c--;
 }

 public synchronized int value()
 {
  return c;
 }
}

„Gute Arbeit. Aber wie würde es aussehen, wenn wir atomare Typen verwenden würden:“

Beispiel
class AtomicCounter
{
 private AtomicInteger c = new AtomicInteger(0);

 public void increment()
 {
  c.incrementAndGet();
 }

 public void decrement()
 {
  c.decrementAndGet();
 }

 public int value()
 {
  return c.get();
 }
}

„Ihre und meine Klasse funktionieren beide auf die gleiche Weise, aber die Klasse mit einem AtomicInteger arbeitet schneller.“

„Na ja, ist das ein kleiner Unterschied?“

„Ja. Aufgrund meiner Erfahrung empfehle ich immer, synchronisiert zu verwenden. Erst wenn der gesamte Anwendungscode geschrieben wurde und der Optimierungsprozess begonnen hat, sollten Sie mit dem Umschreiben des Codes beginnen, um die atomaren Typen zu verwenden. Aber ich wollte Sie auf jeden Fall zu wissen, dass solche Typen existieren. Auch wenn Sie sie nicht aktiv verwenden, besteht immer die Möglichkeit, dass Sie auf Code stoßen, in dem sie verwendet werden.

„Ich stimme zu. Das macht Sinn.“

„Ist Ihnen übrigens aufgefallen, dass die atomaren Typen nicht unveränderlich sind ? Im Gegensatz zur Standard- Integer- Klasse enthält AtomicInteger Methoden zum Ändern seines internen Zustands.“

„Verstanden. Genau wie String und StringBuffer .“

"Ja, etwas in der Art."

Threadsichere Sammlungen.

„Darf ich als Beispiel für eine solche Sammlung ConcurrentHashMap vorstellen. Wie würden Sie HashMap threadsicher machen?“

„Alle Methoden synchronisieren?“

„Sicher, aber stellen Sie sich jetzt vor, Sie hätten eine solche SynchronizedHashMap und Dutzende Threads, die darauf zugreifen. Und hundertmal pro Sekunde wird ein neuer Eintrag zur Karte hinzugefügt, und dabei wird das gesamte Objekt zum Lesen und Schreiben gesperrt.“

„Nun, das ist der Standardansatz. Was können Sie tun?“

„Die Entwickler von Java haben sich ein paar coole Dinge ausgedacht.“

„Zuerst speichern sie Daten in einer ConcurrentHashMap in einem einzigen Block, teilen sie jedoch in Teile auf, die ‚Buckets‘ genannt werden. Und wenn jemand Daten in einer ConcurrentHashMap ändert, sperren wir nur den Bucket, auf den zugegriffen wird, und nicht das gesamte Objekt. Anders.“ Mit anderen Worten, viele Threads können das Objekt gleichzeitig ändern.

„Zweitens: Erinnern Sie sich daran, dass Sie nicht über die Elemente der Liste/Karte iterieren und gleichzeitig die Liste ändern können? Ein solcher Code löst eine Ausnahme aus:“

Durchlaufen Sie nicht die Elemente einer Sammlung in einer Schleife und ändern Sie sie gleichzeitig
HashMap<String, Integer> map = new HashMap<String, Integer>();

for (String key: map.keySet())
{
 if (map.get(key) == 0)
  map.remove(key);
}

„Aber in ConcurrentHashMap können Sie:“

Durchlaufen Sie nicht die Elemente einer Sammlung in einer Schleife und ändern Sie sie gleichzeitig.“
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<String, Integer>();

for (String key: map.keySet())
{
 if (map.get(key) == 0)
  map.remove(key);
}

„Das Concurrent-Paket hat viele Vorteile. Wir müssen diese Klassen nur sehr gut verstehen, um sie nutzen zu können.“

„Ich verstehe. Danke, Kim. Das sind wirklich interessante Kurse. Ich hoffe, dass ich sie eines Tages wie ein Virtuose meistern werde.“