api:documentation:threads:start
Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
Beide Seiten der vorigen RevisionVorhergehende ÜberarbeitungNächste Überarbeitung | Vorhergehende Überarbeitung | ||
api:documentation:threads:start [2024/10/27 20:34] – martin | api:documentation:threads:start [2025/03/05 10:26] (aktuell) – [synchronized-Block] martin | ||
---|---|---|---|
Zeile 1: | Zeile 1: | ||
====== Threads, Synchronisation ====== | ====== Threads, Synchronisation ====== | ||
+ | |||
+ | <WRAP center round info 80%> | ||
+ | Viele aktuelle Prozessoren haben mehr als einen Kern und sind so in der Lage, mehrere Programme gleichzeitig auszuführen. Die Programmiersprache Java ermöglicht es, dies auszunutzen und mehrere Methoden zu starten, die dann gleichzeitig ausgeführt werden. Mann spricht dann von mehreren **Threads** (" | ||
+ | Genauer: | ||
+ | * Falls genug Prozessorkerne zur Verfügung stehen, werden die Threads echt parallel ausgeführt. | ||
+ | * Falls nicht genug Prozessorkerne zur Verfügung stehen, werden die Threads abwechselnd pausiert/ | ||
+ | |||
+ | Um einen Thread parallel zum Hauptprogramm zu starten schreibt man eine Klasse (z.B. '' | ||
+ | <code java> | ||
+ | class MyTask implements Runnable { | ||
+ | void run(){ | ||
+ | // Die Anweisungen, | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | Anschließend übergibt man ein '' | ||
+ | <code java> | ||
+ | Thread t = new Thread(new MyTask()); | ||
+ | t.start(); | ||
+ | |||
+ | // Alle Anweisungen ab hier werden schon parallel zur run-Methode des MyTask-Objekts ausgeführt! | ||
+ | </ | ||
+ | Die '' | ||
+ | </ | ||
+ | |||
+ | ===== Beispiel 1: 11 Threads zählen gleichzeitig ===== | ||
+ | |||
+ | < | ||
+ | |||
+ | <div class=" | ||
+ | |||
+ | <script type=" | ||
+ | SystemTools.setSpeed(8); | ||
+ | |||
+ | class MyTask implements Runnable { | ||
+ | void run() { | ||
+ | for (int i = 0; i < 20; i++) { | ||
+ | | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | |||
+ | for (int j = 0; j < 10; j++) { | ||
+ | | ||
+ | | ||
+ | } | ||
+ | |||
+ | for (int k = 0; k < 10; k++) { | ||
+ | | ||
+ | } | ||
+ | |||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | ====== Race condition und Lösungen ====== | ||
+ | |||
+ | <WRAP center round todo 80%> | ||
+ | Im folgenden Beispiel gibt es **nur ein einziges** Objekt der Klasse '' | ||
+ | Am Ende der Arbeit meldet jeder Thread den aktuellen Zustand des Counters. Man würde erwarten, dass der Thread, der als letztes fertig wird, die Zahl | ||
+ | 3000000 ausgibt. \\ \\ | ||
+ | * Starten Sie das Programm mehrmals und sehen Sie sich die Ausgabe an. | ||
+ | * Wie lässt sich die Ausgabe erklären? | ||
+ | </ | ||
< | < | ||
- | <div class=" | + | <div class=" |
<script type=" | <script type=" | ||
Zeile 11: | Zeile 75: | ||
for (int i = 0; i < 3; i++) { | for (int i = 0; i < 3; i++) { | ||
- | Incrementer | + | Worker |
| | ||
| | ||
Zeile 21: | Zeile 85: | ||
| | ||
+ | long i = counter; | ||
+ | i++; | ||
+ | counter = i; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | |||
+ | class Worker implements Runnable { | ||
+ | |||
+ | | ||
+ | long increment = 0; | ||
+ | |||
+ | | ||
+ | this.increment = increment; | ||
+ | this.counter = counter; | ||
+ | } | ||
+ | |||
+ | | ||
+ | for (long i = 0; i < increment; i++) { | ||
+ | if(i % (increment/ | ||
+ | | ||
+ | } | ||
+ | println(Thread.currentThread().getName() + " done. Counter: " + counter.counter); | ||
+ | } | ||
+ | |||
+ | } | ||
+ | </ | ||
+ | |||
+ | </ | ||
+ | |||
+ | </ | ||
+ | |||
+ | |||
+ | <WRAP center round info 80%> | ||
+ | {{ : | ||
+ | Im rechts stehenden Sequenzdiagramm ist zu sehen, was passiert, wenn zwei Threads gleichzeitig die Methode '' | ||
+ | Man nennt diesen Effekt eine **race condition**. Sie entsteht dadurch, dass die Anweisungen in der Methode '' | ||
+ | </ | ||
+ | |||
+ | ===== Synchronized-Methode ===== | ||
+ | <WRAP center round info 80%> | ||
+ | {{ : | ||
+ | Wir brauchen eine Möglichkeit, | ||
+ | * Vergleichen Sie die Deklaration der Methode '' | ||
+ | * Starten Sie das Programm mehrmals. Erklären Sie die Ausgabe! | ||
+ | </ | ||
+ | |||
+ | < | ||
+ | |||
+ | <div class=" | ||
+ | |||
+ | <script type=" | ||
+ | |||
+ | Counter counter = new Counter(); | ||
+ | |||
+ | for (int i = 0; i < 3; i++) { | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | |||
+ | class Counter { | ||
+ | long counter = 0; | ||
+ | |||
+ | | ||
long i = counter; | long i = counter; | ||
i++; | i++; | ||
Zeile 55: | Zeile 185: | ||
</ | </ | ||
+ | |||
+ | ===== Die Klasse Semaphore ===== | ||
+ | <WRAP center round info 80%> | ||
+ | Ein **Semaphor** ist ein Objekt, das einen Zähler enthält, dessen Wert angibt, von wie vielen Prozessen ein kritischer Abschnitt im Augenblick gerade noch betreten werden darf. \\ (**Bem.:** Eine andere Interpretation besteht darin, dass es $n$ gleichartig Ressourcen gibt. Der Wert des Zählers gibt an, wie viele im Augenblick gerade zur Verfügung stehen.) \\ \\ Der Semaphor besitzt zwei Methoden: | ||
+ | * '' | ||
+ | * Ist dies der Fall, so wird der Zähler um eins erniedrigt und mit der danach folgenden Anweisung fortgefahren. Dem Prozess wird damit das Betreten des kritischen Bereichs gestattet. | ||
+ | * Ist dies **nicht** der Fall, so wird der Prozess in einen Wartezustand versetzt. \\ | ||
+ | * '' | ||
+ | * Falls dies der Fall ist, wir einer davon " | ||
+ | * Ist dies **nicht** der Fall, so wird der Zähler um 1 erhöht. | ||
+ | </ | ||
< | < | ||
- | <div class=" | + | <div class=" |
- | + | ||
- | <script type=" | + | |
+ | <script type=" | ||
Counter counter = new Counter(); | Counter counter = new Counter(); | ||
+ | Semaphore semaphore = new Semaphore(1); | ||
for (int i = 0; i < 3; i++) { | for (int i = 0; i < 3; i++) { | ||
- | | + | |
| | ||
| | ||
Zeile 79: | Zeile 220: | ||
counter = i; | counter = i; | ||
} | } | ||
+ | } | ||
+ | |||
+ | |||
+ | class Incrementer implements Runnable { | ||
+ | |||
+ | | ||
+ | long increment = 0; | ||
+ | int index; | ||
+ | | ||
+ | |||
+ | | ||
+ | this.increment = increment; | ||
+ | this.counter = counter; | ||
+ | this.index = index; | ||
+ | this.semaphore = semaphore; | ||
+ | } | ||
+ | |||
+ | | ||
+ | for (long i = 0; i < increment; i++) { | ||
+ | if(i % (increment / 10) == 0) println(" | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | println(" | ||
+ | } | ||
+ | |||
+ | } | ||
+ | </ | ||
+ | |||
+ | </ | ||
+ | |||
+ | </ | ||
+ | |||
+ | |||
+ | ===== Monitorkonzept ===== | ||
+ | < | ||
+ | |||
+ | <div class=" | ||
+ | |||
+ | <script type=" | ||
+ | BlockingQueue< | ||
+ | |||
+ | for (int i = 0; i < 3; i++) { | ||
+ | new Producer(queue, | ||
+ | new MyConsumer(queue, | ||
+ | } | ||
+ | |||
+ | while (true); | ||
+ | |||
+ | |||
+ | class Producer implements Runnable { | ||
+ | | ||
+ | int count; | ||
+ | int producerIndex; | ||
+ | |||
+ | | ||
+ | this.queue = queue; | ||
+ | this.count = count; | ||
+ | this.producerIndex = producerIndex; | ||
+ | Thread t = new Thread(this); | ||
+ | t.setName(" | ||
+ | t.start(); | ||
+ | } | ||
+ | |||
+ | | ||
+ | while (count > 0) { | ||
+ | | ||
+ | | ||
+ | |||
+ | | ||
+ | } | ||
+ | } | ||
+ | |||
+ | } | ||
+ | |||
+ | class MyConsumer implements Runnable { | ||
+ | | ||
+ | int count; | ||
+ | int consumerIndex; | ||
+ | |||
+ | | ||
+ | this.queue = queue; | ||
+ | this.count = count; | ||
+ | this.consumerIndex = consumerIndex; | ||
+ | Thread t = new Thread(this); | ||
+ | t.setName(" | ||
+ | t.start(); | ||
+ | } | ||
+ | |||
+ | | ||
+ | while (count > 0) { | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | } | ||
+ | |||
+ | } | ||
+ | </ | ||
+ | |||
+ | |||
+ | <script type=" | ||
+ | public class BlockingQueue < T extends Object > { | ||
+ | |||
+ | | ||
+ | | ||
+ | |||
+ | | ||
+ | this.capacity = capacity; | ||
+ | } | ||
+ | |||
+ | | ||
+ | while (queue.size() == capacity) { | ||
+ | | ||
+ | } | ||
+ | |||
+ | queue.add(element); | ||
+ | notify(); // notifyAll() for multiple producer/ | ||
+ | } | ||
+ | |||
+ | | ||
+ | while (queue.isEmpty()) { | ||
+ | | ||
+ | } | ||
+ | |||
+ | T item = queue.remove(); | ||
+ | notify(); // notifyAll() for multiple producer/ | ||
+ | return item; | ||
+ | } | ||
+ | |||
+ | | ||
+ | return queue.size(); | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | ===== synchronized-Block ===== | ||
+ | < | ||
+ | |||
+ | <div class=" | ||
+ | |||
+ | <script type=" | ||
+ | |||
+ | Counter counter = new Counter(); | ||
+ | |||
+ | for (int i = 0; i < 3; i++) { | ||
+ | | ||
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | |||
+ | class Counter { | ||
+ | long counter = 0; | ||
} | } | ||
Zeile 97: | Zeile 395: | ||
for (long i = 0; i < increment; i++) { | for (long i = 0; i < increment; i++) { | ||
if(i % (increment/ | if(i % (increment/ | ||
- | counter.increment(); | + | |
+ | | ||
+ | long i = counter.counter; | ||
+ | i++; | ||
+ | counter.counter = i; | ||
+ | } | ||
+ | |||
} | } | ||
println(" | println(" | ||
Zeile 108: | Zeile 412: | ||
</ | </ | ||
+ | |||
+ |
api/documentation/threads/start.1730061249.txt.gz · Zuletzt geändert: 2024/10/27 20:34 von martin