JAVA-B4
Parallel Computing (Parallelism)
Parallelism
Multithreading
Klassische Threads
Threads & Runnables
Overview
Thread (Begriff)
DruckThread
DruckRunnable
ThreadDemo
Output
Thread Lifecycle
Overview
start()
run()
join()
stop()?
StartRunJoinDemo Example
Von allein endende Threads
Threads mit while(criteria)
Daemon-Threads
Overview
ThreadDaemonDemo
Daemon (Summary)
Thread-Priority
Overview
t.setPriority(..)
MachineThread Klasse (Example)
ThreadPriorityDemo (Example)
Thread Notification
Grundlagen
wait
notify
notifyAll
sleep
sleep vs. wait
Thread Notification Demo
sychronized(monitor)
Notification/Monitor Zusammenfassung
Concurrent API
Vom Thread zur Concurrent API
Was ist Concurrency?
Was ist Concurrency?
Problemstellungen bei herkömmlichen Threads
Features der Concurrent API
Warum: Bedeutung des Umstiegs
Themenüberblick
Technischer Hintergrund
Thread.sleep(0, 500_000)
System.nanoTime()
Executors (Übersicht) #310
ExecutorService (Page)
Begriffsbestimmung
Excetutor
.execute()
ExecutorService (Begriff)
ExecutorService Interface Methoden
Mehrere Callables und Runnables auf einmal starten
Kontrolliertes Beenden
Executors-Utilily Klasse
newCachedThreadPool()
newSingleThreadExecutor()
newFixedThreadPool(int nThreads)
newWorkStealingPool()
newScheduledThreadPool(int corePoolSize)
Beispiel
ForkJoinPool, RecursiveTask, Executors Example#09
A | B1,B2,B3 | C mit Summenbildung.
Executor vs. ExecutorService Example#10
Executors.newFixedThreadPool(2)
Beispiel
Zusammenfassung Executors
Callable, Future #330
Callable Future (Begriff)
Callable Interface (Begriff)
Begriff
Callable erzeugen
Callable verwenden
Future
Beispiel
Future-Listen mit invokeAll
Was sind Future-Listen?
Wie erzeuge ich Future-Listen?
Wann blockt eine Future-Liste?
Beispiel mit 12 Callables in 4 Gruppen
Executors (#350) @! Bis auf Hinweis doppelt
Overview
Executor (Begriff)
ExecutorService (Begriff)
Executors.new~ Factory Methoden
Executors für ThreadPoolExecutor mit fixed Pool
ScheduledExecutorService
ScheduledExecutorService
Superklasse ExecutorService
schedule(*)
scheduleAtFixedRate(*)
scheduleWithFixedDelay(*)
ScheduledExecutorService (xmpl)
ProductClock(Main, Bsp.)
AbstractMachine**
AbstractMaterial**
Coal/Iron/Steel**
Coal-/Iron-/Steel-Machine**
Material**
ProductionBus-Machine**
Storage T**
ThreadPoolExecutor (Detail)
Executor Implementierung
ThreadPoolExecutor (Term)
ThreadPoolExecutor Beispiele
"FixedSizeExecutorExample" EXAMPLE C20
"CachedExecutorExample" EXAMPLE C21
SynchronousQueue
"ScheduledExecutorExample" EXAMPLE C22
"CustomSingleThreadExecutorRunnableComponent" EXAMPLE C23
"CustomPolicyRejectedExecutorExample" EXAMPLE C24
"PrioritizedCombinerRunnableComponent" EXAMPLE C30
"BufferingRejectedTasksExample" EXAMPLE C31
Java RejectedExecutionHandler
ThreadPoolExecutor FAQ
Synchronizer
Synchronizer (overview)
Synchronizer Begriff
CountDownLatch
CountDownLatch Example
CyclicBarrier
CyclicBarrier Example (@Zeit ausgeben!)
Phaser
Phaser Example(@Erl!)
Exchanger
Exchanger ping/pong
Semaphore
CompletableFuture
async!!!
SemaphoreCompletableFutureDemo (@!?)
Monitoring
JMX
ThreadPoolExecutor "live" überwachen
getActiveCount()
getPoolSize()
getCompletedTaskCount()
getQueue().size()
Concurrency
Example:DeterministicCopy @todo FILE LINK FEHLT!
Example:NonDeterministicCopy @todo FILE LINK FEHLT!
Kapitel java.util.concurrent.Flow @!fehltReactive Flow @!fehltPublisher TSubscriber TSubscription TProcressor TProcressor T
Overview
Threads & Runnables | Overview
In einem ersten Schritt zur Einführung in Parallel Computing und damit nebenläufige Programmierung geben wir einen grundlegenden Überblick über die maßgebenden Prinzipien und Begriffe.
Java unterstützt wirkliches Multithreading im Gegensatz zu der ähnlich klingenden Programmiersprache JavaScript, welche single-threaded ist. Dieses führt zu einer ganzen Reihe von Features und damit Fähigkeiten, die Java bietet. Es gilt aber im Gegenzug auch zu verstehen, welche Folgen diese technischen Möglichkeiten haben, wenn man denn die möglichen Problemstellungen nicht kennt.
Threads
Threads & Runnables | Threads (Begriff)
Ein Thread (engl. Faden) ist ein nebenläufiger Prozess welcher in Java auf einem anderem Prozessor laufen kann. Dieses als Multithreading bezeichnete Prinzip bedeutet, dass die main-Methode im MainThread eines Programms neue Threads erzeugen kann, welche ab dem Zeitpunkt, wo diese gestartet werden, die Sequenz von Befehlen deren run() Methode ausführen.
Threads implementieren das Runnable-Interfaces; dieses stellt sicher,
dass Objekte dieser Klassen eine run() Methode haben.
Um Thread-Objekte erzeugen zu können, gibt es mehrere Varianten:
Instanz einer eigenen Thread-Klasse: Man kann eine eigene Klasse von java.util.Thread ableiten und in dieser die run() Methode überschreiben. Die run()-Methode wird aufgerufen, wenn eine Thread-Instanz mit start() gestartet wurde. Die run()-Methode wird NICHT selbst aufgerufen.
Eine zweite Option, einen Thread zu ereugen, besteht darin, dem Thread bei seiner Erzeugung im Konstruktor eine Referenz auf ein Runnable-artiges Objekt zu geben. Darauf gehen wir im Kapitel Runnable ein.
Es gibt noch weitere Varianten. Auf diese gehen wir an dieser Stelle aber jetzt nicht weiter ein.
Threads & Runnables | DruckThread
Wir können jederzeit einen Thread erzeugen, in dem wir eine Klasse von Thread ableiten und die run-Methode überschreiben.
package com.stuelken.java.b4.parallel.c01threads;
/**
* Die {@link DruckThread} Klasse dient für Objekte, welche nicht mehr und nicht
* weniger tun können, als eine Ausgabe, welcher Thread gerade arbeitet.
*
* @author t2m
*/
class DruckThread extends Thread { // {#1}
/**
* Die {@link #run()} Methode überschreibt die {@link Thread#run()} Methode der
* Klasse {@link Thread}
*/
@Override // {#2}
public void run() { // {#3}
int counter = 0; // {#4}
while (counter++ < 5) { // {#5}
System.out.println("DruckThread.run() this.getName() " + this.getName() //
+ " counter=" + counter); // {#6}
try {
Thread.sleep(1000); // {#7}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Threads & Runnables | DruckRunnable
Unser Runnable
Erspart uns das Ableiten von Thread.
package com.stuelken.java.b4.parallel.c01threads;
/**
* {@index "Examples/Thread.currentThread().getName()" "Thread.currentThread().getName()"}
*
* @author t2m
*/
public class DruckTask extends WasAuchImmer implements Runnable { // {#1}
/**
* Die eigentliche Tätigkeit des Runnable
*/
@Override // {2}
public void run() { // {#3}
int counter = 1; // {#4}
String localName = Thread.currentThread().getName(); // {#5}
while (counter++ < 5) { // {#6}
System.out.println( // {#7}
"DruckTask.run() Thread.currentThread().getName()=" + localName //
+ " counter=" + counter); // {#8}
try {
Thread.sleep(1000); // {#10}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Demo
Threads & Runnables | ThreadDemo
Das Programm ThreadDemo startet 5 Threads und Runnables.
package com.stuelken.java.b4.parallel.c01threads;
/**
*
* @author t2m
*/
public class ThreadDemo {
/**
* @param args Keine Argumente
*/
public static void main(String[] args) {
int maxThreadRunnables = 5; // {#1}
Thread[] arrThreadRunnables = new Thread[maxThreadRunnables]; // {#2}
//////////////////////
// Runnable-Variante
//////////////////////
// {#3} Instanzen erzeugen und starten.
for (int i = 0; i < maxThreadRunnables; i++) {
arrThreadRunnables[i] = new Thread(new DruckTask(), "Runnable-Thread-" + i);
arrThreadRunnables[i].start();
}
//////////////////////
// Thread-Variante
//////////////////////
int maxThreadOnly = 5; // {#4}
Thread[] arrThreadOnly = new Thread[maxThreadOnly]; // {#5}
// {#6} Instanze erzeugen und starten.
for (int i = 0; i < maxThreadOnly; i++) {
arrThreadRunnables[i] = new DruckThread();
arrThreadRunnables[i].setName("DruckThread-" + i);
arrThreadRunnables[i].start();
}
//////////////////////
// main-Ende
//////////////////////
System.out.println("main() Methode beendet."); // {#7}
}
}
//@formatter:off
/*
DruckTask.run() Thread.currentThread().getName()=Runnable-Thread-0 counter=2
DruckTask.run() Thread.currentThread().getName()=Runnable-Thread-1 counter=2
DruckTask.run() Thread.currentThread().getName()=Runnable-Thread-2 counter=2
DruckTask.run() Thread.currentThread().getName()=Runnable-Thread-4 counter=2
DruckThread.run() this.getName() DruckThread-0 counter=2
main() Methode beendet.
DruckTask.run() Thread.currentThread().getName()=Runnable-Thread-3 counter=2
DruckThread.run() this.getName() DruckThread-1 counter=2
DruckThread.run() this.getName() DruckThread-2 counter=2
DruckThread.run() this.getName() DruckThread-3 counter=2
DruckThread.run() this.getName() DruckThread-4 counter=2
DruckThread.run() this.getName() DruckThread-2 counter=3
DruckThread.run() this.getName() DruckThread-4 counter=3
DruckThread.run() this.getName() DruckThread-3 counter=3
DruckThread.run() this.getName() DruckThread-0 counter=3
DruckTask.run() Thread.currentThread().getName()=Runnable-Thread-3 counter=3
DruckThread.run() this.getName() DruckThread-1 counter=3
DruckTask.run() Thread.currentThread().getName()=Runnable-Thread-4 counter=3
DruckTask.run() Thread.currentThread().getName()=Runnable-Thread-2 counter=3
DruckTask.run() Thread.currentThread().getName()=Runnable-Thread-1 counter=3
DruckTask.run() Thread.currentThread().getName()=Runnable-Thread-0 counter=3
DruckThread.run() this.getName() DruckThread-2 counter=4
DruckThread.run() this.getName() DruckThread-4 counter=4
DruckTask.run() Thread.currentThread().getName()=Runnable-Thread-1 counter=4
DruckTask.run() Thread.currentThread().getName()=Runnable-Thread-2 counter=4
DruckTask.run() Thread.currentThread().getName()=Runnable-Thread-4 counter=4
DruckTask.run() Thread.currentThread().getName()=Runnable-Thread-0 counter=4
DruckTask.run() Thread.currentThread().getName()=Runnable-Thread-3 counter=4
DruckThread.run() this.getName() DruckThread-1 counter=4
DruckThread.run() this.getName() DruckThread-3 counter=4
DruckThread.run() this.getName() DruckThread-0 counter=4
DruckThread.run() this.getName() DruckThread-2 counter=5
DruckThread.run() this.getName() DruckThread-4 counter=5
DruckTask.run() Thread.currentThread().getName()=Runnable-Thread-3 counter=5
DruckTask.run() Thread.currentThread().getName()=Runnable-Thread-2 counter=5
DruckTask.run() Thread.currentThread().getName()=Runnable-Thread-0 counter=5
DruckThread.run() this.getName() DruckThread-0 counter=5
DruckThread.run() this.getName() DruckThread-3 counter=5
DruckTask.run() Thread.currentThread().getName()=Runnable-Thread-4 counter=5
DruckThread.run() this.getName() DruckThread-1 counter=5
DruckTask.run() Thread.currentThread().getName()=Runnable-Thread-1 counter=5
*/
//@formatter:on
Threads & Runnables | Ausgabe
Die Ausführung der Threads erfolgt nebenläufig parallel. Die Entscheidung, wann welcher Prozessor welchen Thread ausführt, ist in einem gewissen Sinne zufällig.
Die Runnable-Threads beginnen tatsächlich zuerst, aber der 4. Kandidat wird vor dem 3. ausgeführt.
Nachdem die ersten 4 Runnables ausgeführt wurden, wird der erste Thread-0 gestartet und zwischenzeitig dann das Ende der main-Methode erreicht.
Das Programm hat einen kleinen Bug/Fehler.
//@formatter:off
/*
DruckTask.run() Thread.currentThread().getName()=Runnable-Thread-0 counter=2
DruckTask.run() Thread.currentThread().getName()=Runnable-Thread-1 counter=2
DruckTask.run() Thread.currentThread().getName()=Runnable-Thread-2 counter=2
DruckTask.run() Thread.currentThread().getName()=Runnable-Thread-4 counter=2
DruckThread.run() this.getName() DruckThread-0 counter=2
main() Methode beendet.
DruckTask.run() Thread.currentThread().getName()=Runnable-Thread-3 counter=2
DruckThread.run() this.getName() DruckThread-1 counter=2
DruckThread.run() this.getName() DruckThread-2 counter=2
DruckThread.run() this.getName() DruckThread-3 counter=2
DruckThread.run() this.getName() DruckThread-4 counter=2
DruckThread.run() this.getName() DruckThread-2 counter=3
DruckThread.run() this.getName() DruckThread-4 counter=3
DruckThread.run() this.getName() DruckThread-3 counter=3
DruckThread.run() this.getName() DruckThread-0 counter=3
DruckTask.run() Thread.currentThread().getName()=Runnable-Thread-3 counter=3
DruckThread.run() this.getName() DruckThread-1 counter=3
DruckTask.run() Thread.currentThread().getName()=Runnable-Thread-4 counter=3
DruckTask.run() Thread.currentThread().getName()=Runnable-Thread-2 counter=3
DruckTask.run() Thread.currentThread().getName()=Runnable-Thread-1 counter=3
DruckTask.run() Thread.currentThread().getName()=Runnable-Thread-0 counter=3
DruckThread.run() this.getName() DruckThread-2 counter=4
DruckThread.run() this.getName() DruckThread-4 counter=4
DruckTask.run() Thread.currentThread().getName()=Runnable-Thread-1 counter=4
DruckTask.run() Thread.currentThread().getName()=Runnable-Thread-2 counter=4
DruckTask.run() Thread.currentThread().getName()=Runnable-Thread-4 counter=4
DruckTask.run() Thread.currentThread().getName()=Runnable-Thread-0 counter=4
DruckTask.run() Thread.currentThread().getName()=Runnable-Thread-3 counter=4
DruckThread.run() this.getName() DruckThread-1 counter=4
DruckThread.run() this.getName() DruckThread-3 counter=4
DruckThread.run() this.getName() DruckThread-0 counter=4
DruckThread.run() this.getName() DruckThread-2 counter=5
DruckThread.run() this.getName() DruckThread-4 counter=5
DruckTask.run() Thread.currentThread().getName()=Runnable-Thread-3 counter=5
DruckTask.run() Thread.currentThread().getName()=Runnable-Thread-2 counter=5
DruckTask.run() Thread.currentThread().getName()=Runnable-Thread-0 counter=5
DruckThread.run() this.getName() DruckThread-0 counter=5
DruckThread.run() this.getName() DruckThread-3 counter=5
DruckTask.run() Thread.currentThread().getName()=Runnable-Thread-4 counter=5
DruckThread.run() this.getName() DruckThread-1 counter=5
DruckTask.run() Thread.currentThread().getName()=Runnable-Thread-1 counter=5
*/
//@formatter:on
UIO3 Es ist einfacher als Du denkst.
Stelle noch heute Deine Anfrage.
