Parallele Programmierung (3IB)
=> Grundlage: Hettel und Tran (2016, Kap. 2)
Runnable
und im Thread
-Konstruktor Übergebenpublic static void main(String... args) {
// Anzahl der Prozessoren abfragen
var nr = Runtime.getRuntime().availableProcessors();
System.out.println("Anzahl der Prozessoren " + nr);
// Eigenschaften des "main Threads"
var self = Thread.currentThread();
System.out.println("Name : " + self.getName());
System.out.println("Prio : " + self.getPriority());
System.out.println("ID : " + self.threadId());
}
availableProcessors
und Hyper-ThreadingRuntime.getRuntime().availableProcessors()
\(\to\) 8 wegen Hyper-Threading, obwohl 1 CPU mit 4 KernenHettel und Tran (2016, 13)
import org.apache.commons.lang3.ThreadUtils;
/* ... (u.a. printFeatures) ... */
for (var t : ThreadUtils.getAllThreads()) {
printFeatures(t.threadId(), t.getName(), t.getPriority(), t.isDaemon());
}
ID | Name | Priority | isDaemon |
---|---|---|---|
1 | main | 5 | false |
2 | Reference Handler | 10 | true |
3 | Finalizer | 8 | true |
4 | Signal Dispatcher | 9 | true |
12 | Notification Thread | 9 | true |
13 | Common-Cleaner | 8 | true |
OpenJDK 16.0.2 64-Bit Server VM auf Intel Core i5-1145G7 @ 2.60GHz mit 16 GB RAM und x86_64 Linux (Kernel Version: 5.10.70)
Thread
ab und überschreibt die run
-Methode.Runnable
-Interface implementiert. Ein Objekt dieser Klasse wird auch oft als Task bezeichnet. Es wird dann einem Thread
-Objekt zur Ausführung übergeben.Die so vorbereitete Thread
-Instanz wird durch Aufruf der Methode start()
zur nebenläufigen Abarbeitung markiert. Der Java-Scheduler sorgt dafür, dass Kontextwechsel zu diesem Thread erfolgen bzw. dass er in einer Execution-Engine (“Prozessor”) abgearbeitet wird. Wann Wechsel zu diesem Thread erfolgen, liegt aber in der Verantwortung des Schedulers, der eine eigene Strategie verfolgen kann. Die Priority Eigenschaft des Threads sollte dabei berücksichtigt werden.
Main.class
) mit einem System Call undmain
-Methode in einem eigenen Thread (“main Thread”) hier als grüne Lifeline dargestellt.t
Thread
-Objekt instanziiert.start()
aus dem “main Thread” heraus aufgerufen.start()
bewirkt, dass die JVM einen neuen Thread bereitstellt und die run()
Methode von t
darin ausführt.run()
Methode wird nebenläufig zum “main Thread” ausgeführt (blaue Lifeline).pp.01.01-Inheritance
Thread
-Konstruktor und Runnable
public Thread(Runnable target)
public Thread(Runnable target, String name)
Dem Konstruktor von Thread
kann man ein Objekt als Parameter übergeben, das das Runnable
-Interface implementiert. Optional kann auch ein String
für die name
-Eigenschaft mit übergeben werden.
Runnable
-Objektst
Thread
-Objekt instanziiert. Dabei wird der Konstruktor verwendet, der ein “Runnable
-Objekt” als ersten Parameter hat.start()
aus dem “main Thread” heraus aufgerufen.start()
bewirkt, dass die JVM einen neuen Thread bereitstellt, und die run()
Methode von t
darin ausführt.run()
Methode von t
besteht daraus, dass die run()
Methode des “Runnable
-Objekts” ausgeführt wird.run()
Methoden werden nebenläufig zum “main Thread” ausgeführt (blaue Lifelines).Runnable
als anonyme innere KlasseRunnable
als Lambda-AusdruckRunnable
als Lambda-Ausdruck (kurz)Runnable
und Refactoring”pp.01.02-Runnable
void join()
void join(long millis)
void join(long millis,
int nanos)
Die Varianten mit Parameter warten für eine gewisse Zeit. Sollte der Thread, auf dessen Ende gewartet wird, bis dahin nicht beendet sein, geht es trotzdem weiter.
millis == 0
bedeutet “für immer” (genau wie join()
)
Thread
-Objektsabgewandelt aus Hettel und Tran (2016, 19)
(*) Bedingungen: s. nächste Folie
Thread
-Enderun()
-Methoderun()
stop()
am zu beendenden Thread auf (deprecated ebenso wie pause()
und resume()
!)Thread.currentThread().setDaemon(true)
) und alle User-Threads sind beendetSystem.exit()
wird in irgendeinem Thread der JVM aufgerufenThread
-Stoppen durch Signalisieren mit VariableThread
-Stoppen durch Signalisieren mit Variablepublic class Task implements Runnable {
private volatile boolean stopped;
private volatile Thread self;
public boolean isStopped() {
return this.stopped;
}
public void stopRequest() {
this.stopped = true;
if (this.self != null) {
this.self.interrupt();
}
}
@Override
public void run() {
this.self = Thread.currentThread();
while (!isStopped()) {
// ... arbeiten ...
}
// ... aufräumen ...
}
}
Thread
-Stoppen durch Signalisieren mit Variable (Alternative)public class Main {
public static void main(String... args) throws InterruptedException {
var thread = new Task();
thread.start();
Thread.sleep(4000);
thread.stopRequest();
thread.join();
}
}
Alternativ: Hier erbt der nebenläufige Task von Thread
, statt dem Thread
-Konstruktor im “main Thread” ein Runnable
als Parameter zu übergeben.
Thread
-Stoppen durch Signalisieren mit Variable (Alternative)public class Task extends Thread {
private volatile boolean stopped;
private volatile Thread self;
public boolean isStopped() {
return this.stopped;
}
public void stopRequest() {
this.stopped = true;
if (this.self != null) {
this.self.interrupt();
}
}
@Override
public void run() {
this.self = Thread.currentThread();
while (!isStopped()) {
// ... arbeiten ...
}
// ... aufräumen ...
}
Thread
-Stoppen durch Signalisieren mit Variable (Alternative)public class Task extends Thread {
private volatile boolean stopped;
public boolean isStopped() {
return this.stopped;
}
public void stopRequest() {
this.stopped = true;
if (this.isAlive()) {
this.interrupt();
}
}
@Override
public void run() {
while (!isStopped()) {
// ... arbeiten ...
}
// ... aufräumen ...
}
}
pp01.03-EndThread
Thread
-ObjektsBLOCKED
: mehr dazu kommt nächste WocheWAITING
: mehr dazu kommt übernächste WocheTIMED_WAITING
: wartet z.B. wg. Thread.sleep(...)
. Durch interrupt()
kann der Thread zurück zu RUNNABLE
wechseln.abgewandelt aus Hettel und Tran (2016, 26)