88
SYSTEM SOFTWARE 1 Multithreading

Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

  • Upload
    others

  • View
    1

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 1

Multi

Multithreading

Page 2: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 2

Multithreading

Einleitung und Grundlagen

Multithreading Grundlagen

Probleme bei Multithreading

Klassisches Modell

Synchronisation

Threads und Swing

Neues Modell

Executors und Futures

Synchronisation

Concurrent Collections

Fallbeispiel

Zusammenfassung

Page 3: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 4

Klassendiagramm (Auszug)

+run()

«Schnittstelle»

Runnable

+sleep(in millis : boolean)

+interrupt()

+join()

+yield()

+isAlive() : boolean

+isDaemon() : boolean

+isInterrupted() : boolean

+setPriority(in newPriority : int)

+setDaemon(in on : boolean)

Thread1

-runnable

0..1

+enumerate(in list : Thread[]) : int

+enumerate(in list : ThreadGroup[]) : int

+interrupt()

+isDaemon()

+setDaemon()

+setDaemon()

+setPriority()

+activeCount() : int

+getParent() : ThreadGroup

+uncaughtException()

ThreadGroup

1

-threads

*

InterruptedException

Exception

+wait()

+wait(in timeout : long)

+notify()

+notifyAll()

Object

1

-subgroups *

Page 4: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 5

Überblick über Klassen

Thread:

Thread-Objekte repräsentieren einen Thread

definiert Methoden für starten, unterbrechen, …

definiert static-Methoden, um

aktuell laufenden Thread zu steuern, zB ihn schlafen zu legen

Verwaltung aller aktuell existierenden Threads

Runnable:

Interface Runnable definiert Methode run(), welche den von einem Thread

auszuführenden Code enthält

Thread implementiert Runnable

Thread kann mit einem Runnable-Objekt erzeugt werden

Object:

in Klasse Object ist ein Monitor implementiert, d.h. jedes Objekt in Java kann

zur Thread-Synchronisation verwendet werden

wesentlichen Methoden sind wait und notify und notifyAll

ThreadGroup: Für das Bilden von Gruppen von Threads

InterruptedException: Exception geworfen bei Unterbrechung

Page 5: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 6

Erzeugen, Starten, Ablauf eines Threads (1)

Variante: Ableiten von Thread

Thread wird abgeleitet (zB: BallThread) und

run() von Runnable überschrieben

Thread-Objekt wird mit new erzeugt

Thread wird mit start() gestartet und damit

run() ausgeführt

Der Thread läuft bis zum Ende der

Methode run() und stirbt dann

• Die static-Methode sleep(long millis) erlaubt

es, den aktuellen Thread für eine gegebene

Zeit „Schlafen zu legen“

Achtung:

sleep wirft InterruptedException und

muss daher mit try/catch-Anweisung

geklammert werden

class MyApp {

public static void main(...) {

Thread thread = new MyThread();

thread.start();

}

...

}

class MyThread extends Thread {

public void run() {

try {

...

Thread.sleep(1000);

}

catch (InterruptedException e){ ... }

}

}

Beispiel: BallThread

Page 6: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 7

Erzeugen, Starten, Ablauf eines Threads

Die Methode run() wird in einem eigenen Runnable-Objekt implementiert

Thread-Objekt wird mit new erzeugt, wobei das Runnable-Objekt als Parameter

übergeben wird

Thread wird mit start() gestartet und damit run() des Runnable-Objekts ausgeführt

public void startApp…() {

Runnable runnable = new MyRunnable();

Thread thread = new Thread(runnable );

thread.start();

}

class MyRunnable implements Runnable {

public void run() {

try {

Thread.sleep(1000);

}

catch (InterruptedException e){ ... }

}

}

public void startApp…() {

Thread thread = new Thread(() -> {

try {

Thread.sleep(1000);

} catch (InterruptedException e) {

...

}

};

mit Lambdas von Java 8:

Lambda implementiert Runnable

Page 7: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 8

Thread-Zustände

neu: wurde gerade erzeugt und noch

nicht gestartet

lauffähig: aktiv: wird gerade ausgeführt

bereit: kann ausgeführt werden und wartet

auf Zuteilung des Prozessors

blockiert: schlafend: wurde mit sleep schlafen gelegt

IO-blockiert: wartet auf Beendigung einer IO-

Operation

wartend: wurde mit wait in den wartenden

Zustand versetzt

gesperrt: Wartet auf die Aufhebung einer

Objekt-Sperre

suspendiert: durch suspend() vorübergehend

blockiert

Achtung: ist veraltet und sollte nicht

verwendet werden

tot: run()-Methode hat terminiert

blockiert (blocked)

lauffähig (runnable)

neu

(new)

aktiv

(active)

bereit

(ready)

tot

(dead)

schlafend

(sleeping)

IO-blockiert

(IO-blocked)

gesperrt

(locked)

wartend

(waiting)

sleep()

aufw

achen

IO-O

pe

rtio

n

Ende IO

-Opera

tion

Obje

kts

perr

e (

synchro

niz

ed)

Aufh

eben O

bje

kts

perre

wait-

Anw

eis

ung

notify / n

otifyA

ll

sta

rt()

run te

rmin

iert

suspendiert

(suspended)

susp

end() resum

e()

Page 8: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 9

Scheduling und Prioritäten

Threads

geringer

Priorität

Threads

höhrerer

Priorität

Die lauffähigen Threads müssen sich den Prozessor zur Ausführung

teilen; sie konkurrieren um die Zuteilung des Prozessors

Java legt keine Zuteilungsstrategie fest; diese ist abhängig vom

Laufzeitsystem

Starvation

Page 9: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 10

Scheduling und Prioritäten (2)

Mit der Methode

void setPriority(int priority)

kann man einem Thread eine Priorität für die Zuteilung geben

Prioritätswerte liegen zwischen MIN_PRIORITY = 0 undMAX_PRIORITY = 10 mit NORM_PRIORITY = 5 als Standardwert

Beispiel:

Mit der Methode

static void yield()

kann ein Thread seine Kontrolle des Prozessors abgeben und anderen die Chance zur Zuteilung geben.

Runnable r = new MyRunnable();

Thread thread = new Thread(r);

thread.setPriority(priority);

thread.start();

}

Page 10: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 11

Unterbrechung und Terminieren

Unterbrechen von Threads durch

void interrupt()

d.h., befindet sich der Thread in einem blockierten Zustand, wird eine InterruptException

geworfen und der Thread aktiviert.

Mit static-Methode

static boolen interrupted()

wird für den aktuellen Thread der Interrupt-Status abgefragt und rückgesetzt (!)

Interrupts sind für die außerordentliche Terminierung eines Threads wichtig

Anmerkung: Dieses Vorgehen kann die gefährliche stop-Anweisung ersetzen, die nicht mehr

verwendet werden soll

public void run() {

while (!interrupted()) {

try {

// do something

sleep(1000);

} catch (InterruptedException e) { // Fange interrupt in sleep

interrupt(); // Rufe nochmals interrupt() auf,

// um interrupted() zu setzen

}

}

// terminieren

}

Page 11: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 12

Multithreading

Einleitung und Grundlagen

Multithreading Grundlagen

Probleme bei Multithreading

Klassisches Modell

Synchronisation

Threads und Swing

Neues Modell

Executors und Futures

Synchronisation

Concurrent Collections

Fallbeispiel

Zusammenfassung

Page 12: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 13

Probleme

Verzahnte Ausführung

Reihenfolge der Operationen

Unterbrechnung an beliebiger Stelle

Nicht-atomare Operationen

Sichtbarkeit von Daten zwischen Threads (stale data)

Data Race:Bei Schreib- und Leseoperationen in unterschiedlichen

Threads Reihenfolge nicht eindeutig!

Page 13: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 14

Beispiel: Verzahnte Ausführung

Drei nebenläufige Threads:

• Main-Thread

• threadA

• threadB

Schreiboperationen in beliebiger

Reihenfolge

• a=1; x=b(0); b=1; y=a(1); (0, 1)

• b=1; y=a(0); a=1; x=b(1); (1, 0)

• a=1; b=1; y=a(1); x=b(1); (1, 1)

• ...

Umordnung von unabhängigen Statements

durch Compiler erlaubt

• x=b(0); y=a(0); a=1; b=1; (0, 0)

Sichtbarkeit nicht garantiert (stale data): Obwohl ein Thread Variable schreibt, muss neuer Wert

noch nicht für anderen Thread sichtbar sein!

• a=1; b=1; y=a(0); x=b(0); (0, 0)

public class Demo0_RaceConditions {

static int x = 0, y = 0;

static int a = 0, b = 0;

public static void main(String[] args)

throws InterruptedException {

Thread threadA = new Thread(new Runnable() {

@Override

public void run() {

a = 1;

System.out.println("a set");

x = b;

System.out.println("x set");

}

});

Thread threadB = new Thread(new Runnable() {

@Override

public void run() {

b = 1;

System.out.println("b set");

y = a;

System.out.println("y set");

}

});

threadA.start();

threadB.start();

ThreadA.join();

threadB.join();

System.out.println("(" + x + ", " + y + ")");

}

}

threadA ...

x = b;

a = 1;

threadB ...

y = a;

b = 1;

Obwohl threadA a = 1 gesetzt hat, liest threadB noch immer 0

Page 14: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 15

Beispielproblem: Compileroptimierungen

Compiler optimiert Zugriffe für jeden Thread einzeln

Z.B. Register, Cache, Schleifen

class ValueStore implements Runnable {

public int value = 0;

@Override

public void run() {

while (value < 10) {

// no write in this thread

}

System.out.println(“value =" + value);

}

}

public static void main(String[] args) {

final ValueStore store = new ValueStore();

new Thread(store).start();

new Thread(new Runnable() {

@Override

public void run() {

for(;;) {

store.value++;

System.out.println(store.value);

try {

Thread.sleep(300);

} catch (InterruptedException e) {

}

}

}

}).start();

}

Compiler kann while-Bedingung mit true ersetzen, weil value im Thread nicht verändert wird!

Page 15: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 16

Beispielproblem: Keine atomaren Zugriffsoperationen

64-Bit Datentypen werden mit 2 Operationen geschrieben

Dazwischen kann Unterbrechung passieren

class ValueStore {

public long value = 0;

}

class Writer implements Runnable {

private ValueStore store;

Writer(ValueStore store) {

this.store = store;

}

@Override

public void run() {

for (;;) {

store.value = longOp();

try {

Thread.sleep(10);

} catch (InterruptedException e) {…

}

}

}

long longOp() { … }

}

class Reader implements Runnable {

private ValueStore store;

Reader(ValueStore store) {

this.store = store;

}

@Override

public void run() {

for (;;) {

System.out.println(store.value);

try {

Thread.sleep(10);

} catch (InterruptedException e) {…

}

}

}

}

Schreibzugriff nicht atomar

Lesezugriff kann ungültige Daten erhalten

Page 16: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 17

Beispielproblem: Kein wechselseitiger Ausschluss

Beispiel Bank:

Methode transfer subtrahiert Betrag von einem Konto und addiert zum anderen

Mehrere Threads führen gleichzeitig Transfers aus

class Bank {

int[] accounts = new int[NACCOUNTS];

void transfer(int from, int to, int amount) {

account[from] = account[from] - amount;

account[to] = account[to] + amount;

}

thread1 acount[to]thread2

5000

Registerinhalt

laden

addieren

5500speichern

laden

addieren

speichern

5000

Registerinhalt

6000

5000

Inhalt

6000

5500

Page 17: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 18

Beispielproblem: Ungültige Initialisierung

Problem: this-Zeiger verläßt Konstruktor bevor Konstruktor beendet

class EscapedThis {

public static List<EscapedThis> all = new ArrayList<EscapedThis>();

public String msg;

public EscapedThis(String msg) {

all.add(this); // this escapes here

this.msg = msg;

}

}

for (EscapedThis e : EscapedThis.all.toArray(new EscapedThis[0])) {

System.out.println(e.msg.length());

}

this wird in Liste all eingefügt, bevor Konstruktor beendet msg nicht gesetzt

Bei Iteration durch all, wird möglicherweiseauf unitialisiertes Objekt zugegriffen!

NullPointerException

Page 18: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 19

Beispielproblem: Singleton-Pattern

Bei mehreren Threads ist Singleton nicht garantiert

public class SingletonNoLock {

private static SingletonNoLock instance;

public static SingletonNoLock getInstance() {

if (instance == null) {

// do something

instance = new SingletonNoLock();

n++;

}

return instance;

}

}

Dieser Block kann von mehrerenThreads betreten werden Singleton mehrmals erzeugt!

Page 19: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 20

Beispielproblem: Stale Data

class MutableInt {

int x;

public void set(int x) {

this.x =x;

}

public int get() {

return x;

}

}

public class Demo6_MutableInt {

static MutableInt x = new MutableInt();

public static void main(String[] args) {

new Thread(new Runnable() {

@Override

public void run() {

int prev = -1;

for (;;) {

if (prev == x.get()) {

System.out.println("Something strange happened!! ");

}

prev = x.get();

x.set(prev + 1);

}

}

}).start();

new Thread(new Runnable() {

@Override

public void run() {

int prev = -1;

for (;;) {

if (prev == x.get()) {

System.out.println(“Something strange happened!! “);

}

prev = x.get();

x.set(prev + 1);

}

}

}).start();

}

}

Something strange happened!!

3814 3827

Something strange happened!!

4219 4231

Something strange happened!!

44871 44871

Something strange happened!!

48680 48680

Something strange happened!!

55090 55090

Sollte nicht passieren!

Page 20: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 21

Beispielproblem: Unsichere Objektpublikation

public class Holder {

private int n;

public Holder(int n) {

this.n = n;

}

public void assertSanity() {

if (n != n)

throw new AssertionError(„This is due to unsafe publication!");

}

} Wie kann das passieren?

public class Dmeo7_UsafePublication {

static Holder h;

public static void main(String[] args) {

h = new Holder(3);

new Thread(new Runnable() {

public void run() {

h.assertSanity();

}

}

} Kann AssertionError werfen!

Grund: Stale Data

Sichtbarkeit von Objektreferenz

und Feldern zur gleichen Zeit

NICHT garantiert !

Page 21: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 22

Maßnahmen

Zustandslose Methoden

Unveränderbare Objekte (d.h., nur final Felder)

sind grundsätzlich thread-safe

final Variablen vermeiden Stale Data

Single-Thread Rule: Objekte nur in einem Thread verwenden

z.B. Swing

typischerweise 1 Synchronisationspunkt

Thread-sichere Implementierungen mit

atomaren Zugriffen

wechselseitigem Ausschluss

sicherer Objektpublikation

Verwendung von Thread-sicheren Bausteinen

Page 22: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 23

Thread-sichere Implementierungen

„Klasseninvarianten“ müssen auch bei nebenläufigen

Zugriffen immer erhalten bleiben

ohne dass der Client zusätzliche Maßnahmen treffen muss!

Definition: thread-safe

“A class is thread-safe if it behaves correctly when accessed from multiple threads,

regardless of the scheduling or interleaving of the execution of those threads by

the runtime environment, and with no additional synchronization or other

coordination on part of the calling code.”

From: B. Goetz, Java Concurrency in Practice, Addison-Wesley, 2006

Page 23: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 24

Beispielproblem: Thread-sichere Klassen

public class Resource {

int n;

public Resource(int n) {

this.n = n;

}

public boolean seize() {

if (n > 0) {

n--;

return true;

} else {

return false;

}

}

public void release() {

n++;

}

}

Klasse ist nicht Thread-

sicher, weil Invariante

n >= 0 verletzt werden kann!

Durch Unterbrechung und seize() durchanderen Thread kann n hier 0 werden !!

Klasseninvariante: n >= 0

Page 24: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 25

Java Memory Model (JMM):Reihenfolge von Operationen und Sichtbarkeit von Daten

Java Memory Model (JMM)

definiert Bedingungen über Reihenfolge von Operationen und Sichtbarkeit von Werten

bei Shared Data!

„happens-before Relation“

Partielle Ordnung für Synchronisationspunkte

Mit happens-before ist auch Sichtbarkeit der Daten verbunden!

thread A thread B

lock (M)

A

unlock(M)

lock (M)

B

unlock(M)

Thread threadA = new Thread(new Runnable() {

@Override

public void run() {

synchronized (M) {

A;

}

}

});

Thread threadB = new Thread(new Runnable() {

@Override

public void run() {

synchronized(M) {

B;

}

}

});

threadA.start();

threadB.start();

...happens-before

Schreiboperationen in A sichtbar in B

Page 25: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 26

JMM: happens-before

JMM garantiert folgende happens-before Beziehungen

zwischen Synchronisationspunkten

Monitor: Unlock eines Monitors happens-before zeitlich folgende Lock des

selben Monitors

Volatile: Schreiboperation auf volatile Variable happens-before zeitlich

folgende Leseoperation

Thread start: Start eines Threads happens-before allen Operationen des

Threads

Thread termination: jede Operation im Thread happens-before ein anderer

Thread erfährt, dass der Thread terminiert ist

Interrupt: Aufruf von interrupt auf einen Thread happens-before der Thread

erkennt den Interrupt

Finalizer: Ende des Konstruktors happens-before Aufruf des Finalizers

Sequentielle Ordnung: Jeder Synchronisationspunkt happens-before jedem

zeitlich folgenden Synchronisationspunkt innerhalb des gleichen Threads

Page 26: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 27

final Variablen im JMM

JMM behandelt final Variablen gesondert:

Bei final Variablen erfolgt ein value freece am Ende des Konstruktors

Damit ist auch Sichtbarkeit der final Werte für alle Threads gegeben!

Beispiel: Objektpublikation

public class Holder {

private final int n;

public Holder(int n) {

this.n = n;

}

public void assertSanity() {

if (n != n)

throw new AssertionError(„This is due to unsafe publication!");

}

}

Value freece für n Wert sichtbar in allen Threads

Bedingung kann NIE wahr sein!

Page 27: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 28

Multithreading

Einleitung und Grundlagen

Multithreading Grundlagen

Probleme bei Multithreading

Klassisches Modell

Synchronisation

Threads und Swing

Neues Modell

Executors und Futures

Synchronisation

Concurrent Collections

Fallbeispiel

Zusammenfassung

Page 28: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 29

volatile

Kennzeichnung von Variablen als volatile

Effekte von volatile:

Atomare Zugriff auch bei double und long

Sichtbarkeit von anderen Threads garantiert (keine stale Data)

class ValueStore implements Runnable {

public volatile int value = 0;

@Override

public void run() {

while (value < 10) {

// no write in this thread

}

System.out.println(“value =" + value);

}

}

public static void main(String[] args) {

final ValueStore store = new ValueStore();

new Thread(store).start();

new Thread(new Runnable() {

@Override

public void run() {

for(;;) {

store.value++;

System.out.println(store.value);

try {

Thread.sleep(300);

} catch (InterruptedException e) {

}

}

}

}).start();

}

volatile bewirkt atomare Schreiboperationund aktuellen Wert für jeden Thread

Page 29: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 30

Atomic Values

Wrapper-Klassen für Basisdatentypen und Referenzen

• mit atomarem Zugriff

• Zusammengesetzte Opertionen (test and act)

• Sichtbarkeit von mehreren Threads

public class Demo2_AtomicIntegerTest {

static AtomicInteger value = new AtomicInteger(10);

static class ValueWriter implements Runnable {

@Override

public void run() {

for (;;) {

if (! value.compareAndSet(0, 10)) {

System.out.println(value.getAndDecrement());

}

}

}

}

public static void main(String[] args) {

new Thread(new ValueWriter()).start();

new Thread(new ValueWriter()).start();

new Thread(new ValueWriter()).start();

new Thread(new ValueWriter()).start();

}

}

atomar: int prev = valuevalue = value - 1return prev

atomar: if (value == 0) {

value = 10; return true;

} else {return false;

}

Page 30: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 31

Monitor

Basisklasse Object realisiert Monitor für wechselseitigen Ausschluss

Monitor hat einen Schlüssel (Lock) und verwaltet eine Queue

Threads können Lock anfordern

werden eventuell in der Queue als wartend auf den Lock gespeichert

bei Freiwerden des Locks erhält nächster in Queue den Lock und kann

Ausführung fortsetzen

damit kann ein beliebiger Code (aber insbesondere eine Methode des

Objekts) unter exklusivem Zugriff auf das Objekt ausgeführt werden

dies passiert, indem man eine Methode oder einen Block als

synchronized

deklariert

Page 31: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 32

synchronized Methode

Wird eine Methode als synchronized deklariert, muss bei Ausführung der Methode der

Lock des Objekts (this) erhalten werden

Ist dieser nicht verfügbar, kann die Methode nicht begonnen und es muss auf die

Zuteilung des Locks gewartet werden

Bei statischen Methoden wird auf das Klassenobjekt synchronisiert

class Bank {

int[] accounts = new int[NACCOUNTS];

...

synchronized void transfer(int from, int to, int amount) {

accounts[from] -= amount;

accounts[to] += amount;

}

...

}

Page 32: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 33

synchronized Block

Blöcke können auf ein beliebiges Objekt synchronized werden

Block kann nur betreten werden, wenn man den Lock des Objekts hat

class Bank {

private Object accountLock = new Object();

private Object customerLock = new Object();

...

void transfer(int from, int to, int amount) {

synchronized (accountLock) {

account[from] -= amount;

account[to] += amount;

}

}

void addCustomer(Customer customer) {

synchronized (customerLock) {

customers.add(customer);

}

}

}

Page 33: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 34

wait und notify

Soll ein synchronisierter Code nicht fortgesetzt werden, kann er den Lock

zurückgeben und den Thread als „wartend auf das Objekt“ einreihen

Object stellt dazu Methoden zur Verfügung

wait() der Thread wird als wartend auf das Objekt blockiert;

Lock auf das Objekt wird freigegeben

wait(long timeout) wie wait, zusätzlich erfolgt nach timeout Millisekunden ein

Interrupt

notify() Es wird ein (!) auf das Objekt wartender Thread aufgeweckt

notifyAll() Es werden alle auf das Objekt wartenden Threads aufgeweckt

Beispiel: Warten bis Konto gefüllt

synchronized void transfer(int from, int to, int amount) throws InterruptedException {

while (accounts[from] < amount) {

wait();

}

accounts[from] -= amount;

accounts[to] += amount;

notifyAll();

}

Page 34: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 35

Beispiel: BankAccounts (1)

Transferieren von Geld zwischen Konten in mehreren Threads

public class SynchBankTest {

public static final int NACCOUNTS = 10;

public static final int INITIAL_BALANCE = 10000;

public static void main(String[] args) {

Bank b = new Bank(NACCOUNTS, INITIAL_BALANCE);

int i;

for (i = 0; i < NACCOUNTS; i++) {

TransferThread t = new TransferThread(b, i, INITIAL_BALANCE);

t.setPriority(Thread.NORM_PRIORITY + i % 2);

t.start();

}

}

}

Page 35: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 36

Beispiel: BankAccounts (2)

class Bank {

private final int[] accounts;

private long ntransacts;

public Bank(int n, int initialBalance) {

accounts = new int[n];

for (int i = 0; i < accounts.length; i++) {

accounts[i] = initialBalance;

}

ntransacts = 0;

}

public synchronized void transfer(int from, int to, int amount)

throws InterruptedException {

while (accounts[from] < amount) {

wait();

}

accounts[from] -= amount;

accounts[to] += amount;

ntransacts++;

notifyAll();

}

...

}

Page 36: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 37

Beispiel: BankAccounts (3)

class TransferThread extends Thread {

private final Bank bank;

private final int fromAccount;

private final int maxAmount;

public TransferThread(Bank b, int from, int max) {

bank = b;

fromAccount = from;

maxAmount = max;

}

public void run() {

try {

while (!interrupted()) {

int toAccount = (int) (bank.size() * Math.random());

int amount = (int) (maxAmount * Math.random());

bank.transfer(fromAccount, toAccount, amount);

sleep(1);

}

} catch (InterruptedException e) {

}

}

}

Page 37: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 38

Beispiel: Producer – Consumer (1)

public class ProducerConsumerApp {

public static void main(String[] args) {

Buffer buffer = new Buffer();

Producer p = new Producer(buffer);

Consumer c = new Consumer(buffer);

p.start(); // Starten Producer

c.start(); // Starten Consumer

try {

Thread.sleep(10000);

} catch (InterruptedException e) {

// nothing to do

} finally {

p.interrupt();

c.interrupt();

}

}

}

Producer produziert Elemente und schreibt sie in den Puffer

Consumer konsumiert produzierte Elemente aus dem Puffer

public class Buffer {

private Object obj = null;

synchronized public void put(Object o) {

obj = o;

}

synchronized public Object retrieve() {

Object o = obj;

obj = null;

return o;

}

synchronized public boolean isEmpty() {

return obj == null;

}

}

Page 38: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 39

Beispiel: Producer – Consumer (2)

class Producer extends Thread {

private final Buffer buffer;

public Producer(Buffer buffer) { this.buffer = buffer; }

public void run() {

int i = 0;

while (!interrupted()) {

try {

synchronized (buffer) { // Sperren des Puffers

while (!buffer.isEmpty()) {

buffer.wait(); // warte auf buffer leer

}

Object o = new Integer(i++);

buffer.put(o); // Element produzieren

System.out.println(„Produzent erzeugte " + o);

buffer.notifyAll(); // benachrichtige wartende Consumer

}

Thread.sleep((int) (100 * Math.random())); // schlafen

} catch (InterruptedException e) {

interrupt();

}

}

}

}

Page 39: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 40

Beispiel: Producer – Consumer (3)

class Consumer extends Thread {

private final Buffer buffer;

public Consumer(Buffer buffer) {

this.buffer = buffer;

}

public void run() {

while (!interrupted()) {

try {

synchronized (buffer) { // Sperren des Puffers

while (buffer.isEmpty()) {

buffer.wait(); // warte auf buffer nicht leer

}

Object o = buffer.retrieve(); // konsumieren

System.out.println("Konsument fand " + o);

buffer.notifyAll();

}

Thread.sleep((int) (100 * Math.random())); // schlafen

} catch (InterruptedException e) {

interrupt();

}

}

}

}

Page 40: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 41

Collections: unsynchronisierte Collections

Collections sind NICHT thread-safe

Kann zu korrumpierten Daten führen

bei Änderung von Collection, über die man iteriert,

ConcurrentModificationException

static List<Integer> list = new ArrayList<Integer>();

public static void main(String[] args) {Thread a = new Thread(() -> {

for (int i = 1; i < 1000; i++) {…list.add(i);

}});a.start();

Thread b = new Thread(() -> {for (int i = 1000; i < 2000; i++) {

…list.add(i);

}});b.start();

for (int i : list) {…System.out.println(i);

}}

ConcurrentModificationExceptionbei Iteration

add nicht thread-safe

Page 41: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 42

Synchronisierte Collections

Synchronisierte Wrapper für Collections haben thread-safe Zugriff

Achtung: Iteration nicht thread-safe!

static List<Integer> list = Collections.synchronizedList(new ArrayList<Integer>());

public static void main(String[] args) {Thread a = new Thread(() -> {

for (int i = 1; i < 1000; i++) {…list.add(i);

}});a.start();

Thread b = new Thread(() -> {for (int i = 1000; i < 2000; i++) {

…list.add(i);

}});b.start();

for (int i : list) {…System.out.println(i);

}}

add ist thread-safe!

synchronized Wrapper

Iteration NICHT thread-safe!

Page 42: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 43

join

Oft ist es notwendig einen Thread zu erzeugen und den Ablauf mit diesem

abzustimmen

Die Anweisung join erlaubt es, auf einen Thread zu warten, bis dieser terminiert ist.

Beispiel:

Thread t = new Thread(...);

t.start();

// concurrent execution

t.join(); // wait for termination of Thread t

// continue

Page 43: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 45

Ende der Applikation und Daemon-Threads

Eine Applikation wird beendet, wenn alle ihre Threads terminiert (tot) sind

Eine Ausnahme bilden dabei aber die sogenannten Daemon-Threads;

diese werden automatisch beendet, wenn der letzte Nicht-Daemon-Thread einer

Applikation terminiert hat

Daemon-Threads verwendet man daher für Hilfsdienste

Threads können durch Setzen der daemon-Property mit

void setDaemon(boolean on)

zu Daemon-Threads gemacht werden

Page 44: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 46

Veraltete Methoden

stop:

Mit stop() kann man einen Thread „töten“; er wird sofort terminiert

sollte nicht verwendet werden, weil dadurch jede Aktion sofort beendet wird

und dadurch inkonsistente Zustände der bearbeiteten Objekte entstehen

können

Beispiel transfer() bei Bank: Es wird zwar von einem Konto noch

abgehoben aber auf das andere Konto nicht mehr gebucht

suspend / resume:

Mit suspend() kann ein Thread vorübergehend blockiert und mit resume()wieder aufgeweckt werden

dabei gibt er aber Locks von Objekten nicht frei (der Lock kann erst wieder

frei gegeben werden, wenn der Thread mit resume() wieder aufgeweckt

wird)

Dadurch können sehr leicht Deadlocks entstehen, die Verwendung von suspend

wird nicht empfohlen

Page 45: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 47

Multithreading

Einleitung und Grundlagen

Multithreading Grundlagen

Probleme bei Multithreading

Klassisches Modell

Synchronisation

Threads und Swing

Neues Modell

Executors und Futures

Synchronisation

Concurrent Collections

Fallbeispiel

Zusammenfassung

Page 46: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 48

Swing

Swing ist nicht thread-safe

Swing ist nach Single-Thread Regel gebaut

alle Aufrufe auf Swing-Komponenten in einem Thread

AWT-Thread

Arbeitet Ereignisqueue ab:

Zeichnen (paint)

Events: actionPerformed, mouseClicked, …

Page 47: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 49

Blockieren von UI

Keine lang laufenden und blockierenden Aufrufe in Event-Methoden

blockieren UI

public class Demo1_BlockingCall {private static JFrame frame;private static JList list;private static DefaultListModel listModel;private static JButton addBtn;

public static void main(String[] args) throws InterruptedException {frame = new JFrame("AWT Thread Test");listModel = new DefaultListModel();list = new JList(listModel);frame.getContentPane().add(list, BorderLayout.CENTER);…addBtn = new JButton("Add");addBtn.addActionListener(new ActionListener() {

@Overridepublic void actionPerformed(ActionEvent e) {

Out.print("Wert eingeben: ");int x = In.readInt();listModel.addElement(x);

}});

Blockiert UIBlockiert UI

Page 48: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 50

Eigener Thread

Ausführung lang laufender und blockierender Operationen in eigenem Thread

Updates außerhalb AWT Thread

Verletzt Single-Thread Regel von Swing!

…add1Btn.addActionListener(new ActionListener() {

@Overridepublic void actionPerformed(ActionEvent e) {

new Thread(new Runnable() {@Overridepublic void run() {

Out.print("Wert eingeben: ");x = In.readInt();listModel.addElement(x);

}}).start();

}});

in eigenem Thread ausgeführt

in AWT Thread ausgeführt

Page 49: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 51

Eigener Thread

Führt zu Fehlverhalten von Swing

private static int y = 0;public static void main(String[] args) throws InterruptedException {

…add100Btn = new JButton("Add 100");add100Btn.addActionListener(new ActionListener() {

@Overridepublic void actionPerformed(ActionEvent e) {

new Thread(new Runnable() {

@Overridepublic void run() {

for (int i = 0; i < 100; i++) {listModel.addElement(y++);

}}

}).start();}

});

JList funktioniert nicht mehr!

Anfügen von 100 Elementen in ListModel

Page 50: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 52

invokeLater und invokeAndWait

Über EventQueue lassen sich Tasks in die AWT Ereignisqueue einfügen

invokeLater: Einfügen als zukünftige Aufrufe (asynchron)

invokeAndWait: Einfügen und blockieren bis ausgeführt

Merke: Alle Operationen aus anderen Threads, die UI-Elemente updaten, sollen über invokeLater oder invokeAndWait abgesetzt werden!

private static int y = 0;public static void main(String[] args) throws InterruptedException {

…add1Btn.addActionListener(new ActionListener() {

@Overridepublic void actionPerformed(ActionEvent e) {

new Thread(new Runnable() {@Overridepublic void run() {

Out.print("Wert eingeben: ");x = In.readInt();EventQueue.invokeLater(new Runnable() {

public void run() {listModel.addElement(x);

}});

}}).start();

}});

Einplanen des Updates in AWT EventQueue

Page 51: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 53

invokeLater und invokeAndWait

Beispiel invokeAndWait: Anfügen von 100 Elementen

private static int y = 0;public static void main(String[] args) throws InterruptedException {

…add100Btn.addActionListener(new ActionListener() {

@Overridepublic void actionPerformed(ActionEvent e) {

new Thread(new Runnable() {@Overridepublic void run() {

for (int i = 0; i < 100; i++) {y++;try {

EventQueue.invokeAndWait(new Runnable() {public void run() {

listModel.addElement(y);}

});} catch (InterruptedException e) {} catch (InvocationTargetException e) {}

}}

}).start();}

});

Blockiert bis AWT Thread Task ausgeführt hat

Page 52: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 54

invokeLater und invokeAndWait

Beispiel invokeLater:

Mit invokeLater werden Tasks nur abgesetzt

AWT Thread führt Tasks später aus

Absetzen und Ausführung zu unterschiedlichen Zeiten

add100LaterBtn.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {

new Thread(new Runnable() {@Overridepublic void run() {

for (int i = 0; i < 100; i++) {y++;EventQueue.invokeLater(new Runnable() {

public void run() {listModel.addElement(y);

}});try { Thread.sleep(1); } catch (InterruptedException e) {}

}}

}).start();}

});

Einplanen von Task

Bei Ausführung durch AWT Thread ist Wert von y schon 100

Page 53: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 55

Multithreading

Einleitung und Grundlagen

Multithreading Grundlagen

Probleme bei Multithreading

Klassisches Modell

Synchronisation

Threads und Swing

Neues Modell

Executors und Futures

Synchronisation

Concurrent Collections

Fallbeispiel

Zusammenfassung

Page 54: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 56

Executors und Futures

Executors, ExecutorService

Ausführung von Task in mehrere Threads

Abstraktion von konkreten Threads

Future<T>

Ergebnis und Steuerung von asynchronen Berechnungen

Callable<T>

Ausführbares Objekt analog zu Runnable

mit Rückgabewert vom Typ T

seit Java 1.5

Bei vielen Tasks wesentlich effizienter als Threads!

Page 55: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 57

Callable, Future, FutureTask

Callable<T>-Intefacewie Runnable aber erlaubt Rückgabewerte (vom Typ T)

Future<T>-Interfacerepräsentiert Ergebnis einer asynchronen Berechnung

erlauben Zugriff und Eingriff in Ausführung

RunnableFuture<T>-InterfaceKombination von Runnable und Future

FutureTask<T>-KlasseImplementierung von RunnableFuture

public class FutureTask<V> extends Object implements RunnableFuture<V> {

}

public interface Future<V> {

public boolean isCancelled()

public boolean isDone()

public boolean cancel(boolean mayInterruptIfRunning)

public V get() throws InterruptedException, ExecutionException

public V get(long timeout, TimeUnit unit)

}

public interface RunnableFuture<V> extends Runnable, Future<V> {

void run()

}

public interface Callable<V> {

V call() throws Exception

}

get-Methoden blockieren, bis Berechnung fertig

Page 56: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 58

Executor / ExecutorService

erlaubt Berechnungen abzusetzen

in ThreadPool auszuführen

Ergebnis über Future abzuholen

Steuerung der Ausführungseinheit (ThreadPool)

public interface Executor {

void execute(Runnable command)

}

public interface ExecutorService extends Executor {

void shutdown()

List<Runnable> shutdownNow()

boolean isShutdown()

boolean isTerminated()

boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException

<T> Future<T> submit(Callable<T> task)

<T> Future<T> submit(Runnable task, T result)

Future<?> submit(Runnable task)

<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)

throws InterruptedException

<T> T invokeAny(Collection<? extends Callable<T>> tasks)

throws InterruptedException, ExecutionException

}

Page 57: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 59

ThreadPool

Implementierung von ExecutorService

mittels einer Menge von Threads

Threads für unterschiedliche Berechnungen wiederverwendbar

durch statische Methoden von Executors erzeugt

Klasse ThreadPoolExecutor erlaubt Konfiguration des ThreadPools

Threads sind eine teure Ressource!

public class Executors {

public static ExecutorService newFixedThreadPool(int nThreads)

public static ExecutorService newCachedThreadPool()

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)

public static ExecutorService newSingleThreadExecutor()

...

}

public class ThreadPoolExecutor extends AbstractExecutorService {

public int getActiveCount()

public long getTaskCount()

public long getCompletedTaskCount()

public int getPoolSize()

public int getCorePoolSize()

public void setCorePoolSize(int corePoolSize)

public int getMaximumPoolSize()

public void setMaximumPoolSize(int maximumPoolSize)

...

}

Page 58: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 60

Executor / ExecutorService

Beispiel

public class ExecutorServiceDemo {

public static void main(String[] args)

throws InterruptedException, ExecutionException {

ExecutorService e = Executors.newFixedThreadPool(10);

Future<Integer> future = e.submit(() -> {

// long lasting computation

return result;

});

// continue with some with some other work in main thread

int result = future.get();

}

}

Erzeugen eines ExecutorService überstatische Methoden von Executors

Anfügen von Runnables und Callablesbeim ExecutorService

Abholen der Ergebnisse der Callables später über Future

Page 59: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 64

Fork-Join Pool

Fork-Join API

ForkJoinPool stellt Thread-Pool mit „Work-Stealing“ bereit

Tasks werden im ForkJoinPool ausgeführt und können weitere Tasks erzeugen

Im ForkJoinPool erfoglt „Work Stealing“, d.h. sobald ein Task blockiert, wird

Thread freigegeben, damit er andere Aufgaben übernehmen kann

RecursiveTask und RecursiveAction sind Basisklassen für rekursive hierarchische

Taskstrukturen

ForkJoinTask<V>

ForkJoinTask<V> fork()

static void invokeAll

(ForkJoinTask<?>... tasks)

V join()

...

ForkJoinPool

invoke(ForkJoinTask)

execute(ForkJoinTask)

submit(ForkJoinTask)

RecursiveTask<V>

abstract V compute

RecursiveAction

abstract void compute

Page 60: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 65

Ausführung durch Fork-Join

Fork-Join funktioniert nach dem Divide&Conquer Prinzip

RecursiveTasks spalten rekursiv Untertasks ab

diese werden durch Fork-Join Thread-Pool ausgeführt

Prinzip von RecursiveTasks

public class MyRecursiveTask<T> extends RecursiveTask<T> {

@Overrideprotected T compute() {

if (problem small) {result = solve problem sequentially return result;

}

split sub-problem and create subtask for sub-problem send task to fork-join pool... possibley more splits

join with subtasks for partial solutions

result = combine partial solutions return result;

}

Ist Problem klein genug,

löse es sequentiell

Spalte Teilprobleme ab und schicke diese zur

Ausführung an Fork-Join Thread-Pool

Warte auf Lösung der Teilprobleme

Kombiniere Teilprobleme und gib

Gesamtlösung zurück

Page 61: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 66

Fork-Join Pool: Work Stealing

Fork-Join Pool

fixe Anzahl von Threads (abhängig von Anzahl Cores, z.B. 3)

jeder Thread verwaltet eine Queue von Tasks

fork() spaltet Task ab und stellt in Queue des aktuellen Threads

arbeitet mit Work Stealing

untätige Threads „stehlen“ sich Tasks aus Queue anderer Threads

Threads die Tasks ausführen, die mit join() auf Ergebnisse anderer Tasks warten,

suchen sich anderen Aufgaben

T

2

worker-1

T1

worker-2

T

3

fork()

fork()T

3steal T3

Damit wird eine gleichmäßige Auslastung der Threads erreicht!

Page 62: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 68

ScheduledExecutorService

verzögerte Aktivitäten

periodische Aktivitäten

CompletionService<V>, ExecutorCompletionService<V>

unterstützt asynchrones Abholen von Ergebnissen der gesendeten Aufgaben

Weitere Klassen

public interface ScheduledExecutorService extends ExecutorService {

<V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit)

ScheduledFuture<?> schedule(Runnable cmd, long delay, TimeUnit unit)

ScheduledFuture<?> scheduleAtFixedRate(Runnable cmd, long initDelay, long period, TimeUnit unit)

...

}

public interface CompletionService<V> {

Future<V> submit(Callable<V> task)

Future<V> submit(Runnable task, V result)

Future<V> take() throws InterruptedException

Future<V> poll()

Future<V> poll(long timeout, TimeUnit unit)

throws InterruptedException // poll with waiting time

}

public class ExecutorCompletionService<V> implements CompletionService<V> {

public ExecutorCompletionService(Executor executor)

...

}

Blockiert, bis nächstes Ergebnis verfügbar

liefert nächstes Ergebnis oder null, wenn keines verfügbar

wie poll aber wartet timeoutZeiteinheiten

Page 63: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 69

Multithreading

Einleitung und Grundlagen

Multithreading Grundlagen

Probleme bei Multithreading

Altes Modell

Synchronisation

Threads und Swing

Neues Modell

Executors und Futures

Synchronisation

Concurrent Collections

Fallbeispiel

Zusammenfassung

Page 64: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 70

Synchronizers

Lock und Conditions

effizientere und flexiblere Variante von Monitor bei Object

CountDownLatch

Initialisierung mit fixem Wert

await(): Warten bis Zähler auf 0

countDown(): Herunterzählen

Semaphore

Zugriff auf beschränkte Resource mit n Berechtigungen

über acquire() und release()

CyclicBarrier

Zusammenkunft mehrerer Threads

Exchanger

Datenaustausch

SynchronousQueue

Synchroner Übergabe eines Wertes

Page 65: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 71

Lock und Condition

Lock und Condition als effizientere und flexiblere Alternative zu Object

class BankWithLock {

private Lock bankLock;

private Condition sufficientFunds;

public BankWithLock(int n, double initialBalance) {

bankLock = new ReentrantLock();

sufficientFunds = bankLock.newCondition();

accounts = new double[n];

for (int i = 0; i < accounts.length; i++)

accounts[i] = initialBalance;

}

public void transfer(int from, int to, double amount) throws InterruptedException {

bankLock.lock();

try {

while (accounts[from] < amount)

sufficientFunds.await();

}

accounts[from] -= …

sufficientFunds.signalAll();

} finally {

bankLock.unlock();

}

}

Page 66: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 72

Lock und Condition

Locks für jedes Konto

class BankWithMultipleLocks {

private Lock[] accountLocks;

private Condition[] sufficientFunds;

public BankWithLock(int n, double initialBalance) {

accounts = new double[n];

accountLocks = new ReentrantLock[n];

sufficientFunds = new Condition[n];

for (int i = 0; i < accounts.length; i++) {

accountLocks[i] = new ReentrantLock();

sufficientFunds[i] = accountLocks[i].newCondition();

accounts[i] = initialBalance;

}

}

public void transfer(int thread, int from, int to, double amount)throws … {

accountLocks[from].lock();

accountLocks[to].lock();

try {

while (accounts[from] < amount)

sufficientFunds[from].await();

accounts[from] -= amount;

accounts[to] += amount;

sufficientFunds[to].signalAll();

} finally {

accountLocks[from].unlock();

accountLocks[to].unlock();

}

}

}

Deadlock!

Page 67: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 74

Lock: tryLock

tryLock mit Timeout verhindert Deadlocks

public void transfer(int thread, int from, int to, double amount) throws … {

System.out.println(thread + ": waiting " + from);

if (accountLocks[from].tryLock(1000, TimeUnit.MILLISECONDS)) {

try {

if (accountLocks[to].tryLock(1000, TimeUnit.MILLISECONDS)) {

try {

while (accounts[from] < amount) sufficientFunds[from].await();

accounts[from] -= amount;

accounts[to] += amount;

sufficientFunds[to].signalAll();

} finally {

accountLocks[to].unlock();

}

} else {

System.out.println(thread + ":failed to get lock for " + to);

}

} finally {

accountLocks[from].unlock();

}

} else {

System.out.println(thread + ":failed to get lock for " + from);

}

}

Page 68: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 75

Beispiel CountDownLatch

public class CountDownLatchDemo {private CountDownLatch startGate; private CountDownLatch endGate;

public void startTasks(Task[] tasks) {try {

startGate = new CountDownLatch(1); endGate = new CountDownLatch(tasks.length); for (Task task : tasks) {

new Thread(task).start(); }System.out.println("startet"); long startTime = System.nanoTime(); startGate.countDown(); endGate.await(); System.out.format("finished with run time %d", System.nanoTime() - startTime);

} catch (InterruptedException ex) { … }}

class Task implements Runnable {@Override

public void run() {try {

startGate.await(); // do something …..

} finally {endGate.countDown();

}}

}…

}

wait that all tasks are started

wait that all tasks are finished

Page 69: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 76

Multithreading

Einleitung und Grundlagen

Multithreading Grundlagen

Probleme bei Multithreading

Klassisches Modell

Synchronisation

Threads und Swing

Neues Modell

Executors und Futures

Synchronisation

Concurrent Collections

Fallbeispiel

Zusammenfassung

Page 70: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 77

Concurrent Collections

Package java.util.concurrent

Optimiert für Zugriffe aus mehreren Threads

Werfen keine ConcurrentModificationExceptions

Erweiterte atomare Zugriffe wie z.B. putIfAbsent, replace

Interface Concurrent Implemenation

Map ConcurrentHashMap

Set CopyOnWriteArraySet

SortedMap ConcurrentSkipListMap

SortedSet ConcurrentSkipListSet

List CopyOnWriteArrayList

BlockingQueue ArrayBlockingQueue

ConcurrentLinkedQueue

The Iterator is a "weakly consistent" iterator that will never throw ConcurrentModificationException,

and guarantees to traverse elements as they existed upon construction of the iterator,

and may (but is not guaranteed to) reflect any modifications subsequent to construction.

Page 71: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 78

Concurrent Collections

Synchronisierte Wrapper für Collections haben thread-safe Zugriff

Auch Iteration nun thread-safe!!

static Queue<Integer> list = new ConcurrentLinkedQueue<Integer>();

public static void main(String[] args) {Thread a = new Thread(() -> {

for (int i = 1; i < 1000; i++) {…list.add(i);

}});

a.start();

Thread b = new Thread(() -> {for (int i = 1000; i < 2000; i++) {

…list.add(i);

}});b.start();

for (int i : list) {…System.out.println(i);

}

add ist thread-safe!

concurrent collection

Iteration thread-safe!

Page 72: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 79

BlockingQueue

Methoden mit unterschiedlichen Reaktionen, wenn Bedingung für

Zugriff nicht erflüllt (Liste leer oder voll):

add, remove, element werfen Exceptions

put und take blockieren bis Bedingung erfüllt

offer, poll und peek liefern Werte, die Erfolg oder Misserfolg anzeigen

offer und poll blockieren bestimmte Zeit, bis Bedingung erfüllt; kehren dann

mit Rückgabewert zurück

Throw

exceptions

Return special

valueBlock Time out

Insert add(e) offer(e) put(e) offer(e, timeout, timeunit)

Remove remove() poll() take() poll(timeout, timeunit)

Examine element() peek() not applicable not applicable

Blockieren für angegebeneTimeout-Zeit!

Page 73: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 80

Beispiel: Producer-Consumer mit BlockingQueue

public class ProducerConsumerApp {private static final int CAPACITY = 3;public static void main(String[] args) {

BlockingQueue<Integer> buffer = new ArrayBlockingQueue<Integer>

(CAPACITY, true);Producer p1 = new Producer(buffer);Producer p2 = new Producer(buffer);Consumer c1 = new Consumer(buffer);Consumer c2 = new Consumer(buffer);p1.start(); p2.start(); c1.start(); c2.start(); …

}}

import java.util.concurrent.ArrayBlockingQueue;import java.util.concurrent.BlockingQueue;class Producer extends Thread {

private BlockingQueue<Integer> buffer;public Producer(BlockingQueue buffer) {

this.buffer = buffer;}public void run() {

int i = 0;while (!interrupted()) {

try {Integer o = new Integer(i++);buffer.put(o); System.out.println("Produziert " + o);

} catch (InterruptedException ex) {}

}}

}class Consumer extends Thread {

private BlockingQueue buffer;public Consumer(BlockingQueue buffer) {

this.buffer = buffer;}public void run() {

while (!interrupted()) {try {

Object o = buffer.take(); System.out.println("Konsumiert " + o);

} catch (InterruptedException ex) {}

}}

}

Blockiert, wenn buffer voll

Blockiert, wenn buffer leer

This class supports an optional fairness policy for ordering

waiting producer and consumer threads. By default, this

ordering is not guaranteed. However, a queue constructed

with fairness set to true grants threads access in FIFO

order. Fairness generally decreases throughput but reduces

variability and avoids starvation.

Page 74: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 81

Multithreading

Einleitung und Grundlagen

Multithreading Grundlagen

Probleme bei Multithreading

Klassisches Modell

Synchronisation

Threads und Swing

Neues Modell

Executors und Futures

Synchronisation

Concurrent Collections

Fallbeispiel

Zusammenfassung

Page 75: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 82

Beispiel Total File Size

Folgend mehrere Varianten eines Verfahrens zur Ermittlung der

Gesamtgröße der Files in Directory

Sequentielles Verfahren: public class SequentialTotalFileSize {

private long getTotalSizeOfFilesInDir(final File file) {if (file.isFile())

return file.length();final File[] children = file.listFiles();long total = 0;if (children != null)

for (final File child : children)total += getTotalSizeOfFilesInDir(child);

return total;}

public static void main(final String[] args) {final long start = System.nanoTime();final long total = new TotalFileSizeSequential().getTotalSizeOfFilesInDir(new File(args[0]));final long end = System.nanoTime();System.out.println("TotalFileSizeSequential");System.out.println("Total Size: " + total);System.out.println("Time taken: " + (end - start) / 1.0e9);

}}

> java SequentialTotalFileSize C:\Users\hpSequentialTotalFileSizeTotal Size: 83623093266Time taken: 34.442712065

> java SequentialTotalFileSize C:\Users\hpSequentialTotalFileSizeTotal Size: 83689700425Time taken: 17.180551995

Ergebnisse sehr abhängig von Caching im Betriebssystem !

aus: V. Subramaniam: Programming Concurrency on the JVM

Page 76: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 83

Beispiel Total File Size: Variante 1 (1/2)

Total File Size mit Callables und Futures public class NaivelyConcurrentTotalFileSize {

private long getTotalSizeOfFilesInDir(final ExecutorService service, final File file) throws InterruptedException, ExecutionException, TimeoutException {

if (file.isFile())return file.length();

long total = 0;final File[] children = file.listFiles();if (children != null) {

final List<Future<Long>> partialTotalFutures = new ArrayList<Future<Long>>();for (final File child : children) {

partialTotalFutures.add(service.submit(new Callable<Long>() {public Long call() throws InterruptedException, ExecutionException, TimeoutException {

return getTotalSizeOfFilesInDir(service, child);}

}));}for (final Future<Long> partialTotalFuture : partialTotalFutures)

total += partialTotalFuture.get(100, TimeUnit.SECONDS);}return total;

}

private long getTotalSizeOfFile(String fileName) throws InterruptedException, ExecutionException, TimeoutException {

final ExecutorService service = Executors.newFixedThreadPool(100);try {

return getTotalSizeOfFilesInDir(service, new File(fileName));} finally {

service.shutdown();}

}...

get ist ein blockierenden Aufruf Task ist blockiert, belegt aber weiterhin den Thread

aus: V. Subramaniam: Programming Concurrency on the JVM

Page 77: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 84

Beispiel Total File Size: Variante 1 (2/2)

Analyse:

Nach Absetzen der Callables ist Task in Future.get blockiert

Thread wird aber nicht frei gegeben

Dem System gehen die Threads in ThreadPool aus

Resultat ist ein „pool induced deadlock“

Arbeiten mit Futures allgemein problematisch, weil Ergebnis nur durch

blockierenden Call abholbar!

...public static void main(final String[] args) throws InterruptedException,

ExecutionException, TimeoutException {final long start = System.nanoTime();final long total = new NaivelyConcurrentTotalFileSize().getTotalSizeOfFile(args[0]);final long end = System.nanoTime();System.out.println("NaivelyConcurrentTotalFileSize");System.out.println("Total Size: " + total);System.out.println("Time taken: " + (end - start) / 1.0e9);

}}

> java NaivelyConcurrentTotalFileSize C:\Users\hpException in thread "main" java.util.concurrent.TimeoutExceptionat java.util.concurrent.FutureTask.get(FutureTask.java:201)at pcj.NaivelyConcurrentTotalFileSize.getTotalSizeOfFilesInDir(NaivelyConcurrentTotalFileSize.java:44)at pcj.NaivelyConcurrentTotalFileSize.main(NaivelyConcurrentTotalFileSize.java:64)

Verfahren bricht mit Timeout ab!

aus: V. Subramaniam: Programming Concurrency on the JVM

Page 78: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 85

Beispiel Total File Size: Variante 2 (1/2)

Total File Size mit Sammlung von Teilergebnissen eines Directories ohne

rekursive Aufrufepublic class ConcurrentTotalFileSize {

private long getTotalSizeOfFilesInDir(final File file)throws InterruptedException, ExecutionException, TimeoutException {

final ExecutorService service = Executors.newFixedThreadPool(100);

try {long total = 0;final List<File> directories = new ArrayList<File>();directories.add(file);while (!directories.isEmpty()) {

final List<Future<SubDirsAndSize>> partialResults = new ArrayList<Future<SubDirsAndSize>>();for (final File directory : directories) {

partialResults.add(service.submit(new Callable<SubDirsAndSize>() {public SubDirsAndSize call() {

return getTotalAndSubDirs(directory);}

}));}directories.clear();for (final Future<SubDirsAndSize> partialResultFuture : partialResults) {

final SubDirsAndSize subDirectoriesAndSize = partialResultFuture.get(100, TimeUnit.SECONDS);directories.addAll(subDirectoriesAndSize.subDirs);total += subDirectoriesAndSize.size;

}}return total;

} finally {service.shutdown();

}}...

class SubDirsAndSize {final public long size;final public List<File> subDirs;

public SubDirsAndSize(long ts, List<File> sd) {size = ts;subDirs = sd;

}}

Absetzen von Task pro File

Abholen der Ergebnisse

Aufnahme der gefundenen Subdirectories in Liste der noch zu verarbeitenden

Solange nicht alle Subdirectories

verarbeitet

aus: V. Subramaniam: Programming Concurrency on the JVM

Page 79: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 86

Beispiel Total File Size: Variante 2 (2/2)

...private SubDirectoriesAndSize getTotalAndSubDirs(final File file) {

long total = 0;final List<File> subDirectories = new ArrayList<File>();if (file.isDirectory()) {

final File[] children = file.listFiles();if (children != null)

for (final File child : children) {if (child.isFile())

total += child.length();else

subDirectories.add(child);}

}return new SubDirectoriesAndSize(total, subDirectories);

}

public static void main(final String[] args) throws InterruptedException,ExecutionException, TimeoutException {

final long start = System.nanoTime();final long total = new ConcurrentTotalFileSize().getTotalSizeOfFilesInDir(new File(args[0]));final long end = System.nanoTime();System.out.println("ConcurrentTotalFileSize");System.out.println("Total Size: " + total);System.out.println("Time taken: " + (end - start) / 1.0e9);

}}

> java ConcurrentTotalFileSize C:\Users\hpConcurrentTotalFileSizeTotal Size: 5696929234Time taken: 13.404754691

> java ConcurrentTotalFileSize C:\Users\hpConcurrentTotalFileSizeTotal Size: 5695150268Time taken: 11.58708715

aus: V. Subramaniam: Programming Concurrency on the JVM

Page 80: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 87

Beispiel Total File Size: Variante 3 (1/2)

Total File Size mit Teilergebnisse von Tasks in AtomicLong addiert

und CountDownLatch zur Synchronisation

public class ConcurrentTotalFileSizeWLatch {

private ExecutorService service;final private AtomicLong pendingTasks = new AtomicLong();final private AtomicLong totalSize = new AtomicLong();final private CountDownLatch latch = new CountDownLatch(1);

private void updateTotalSizeOfFilesInDir(final File file) {long fileSize = 0;if (file.isFile())

fileSize = file.length();else {

final File[] children = file.listFiles();if (children != null) {

for (final File child : children) {if (child.isFile())

fileSize += child.length();else {

pendingTasks.incrementAndGet();service.execute(new Runnable() {

public void run() {updateTotalSizeOfFilesInDir(child);

}});

}}

}}totalSize.addAndGet(fileSize);if (pendingTasks.decrementAndGet() == 0)

latch.countDown();}...

Absetzen von Task pro FileRaufzählen von pendingTasks

Update von fileSize thread-safe

Update pendingTasks + CountDownLatch thread-safe

aus: V. Subramaniam: Programming Concurrency on the JVM

thread-safe Objekte

Page 81: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 88

Beispiel Total File Size: Variante 3 (2/2)

ConcurrentTotalFileSizeWLatch

Total Size: 83663127072

Time taken: 20.903119452

...private long getTotalSizeOfFile(final String fileName)

throws InterruptedException {service = Executors.newFixedThreadPool(100);pendingFileVisits.incrementAndGet();try {

updateTotalSizeOfFilesInDir(new File(fileName));latch.await(100, TimeUnit.SECONDS);return totalSize.longValue();

} finally {service.shutdown();

}}

public static void main(final String[] args) throws InterruptedException,ExecutionException, TimeoutException {

final long start = System.nanoTime();final long total = new ConcurrentTotalFileSizeWLatch().getTotalSizeOfFile(args[0]); final long end = System.nanoTime();System.out.println("ConcurrentTotalFileSizeWLatch");System.out.println("Total Size: " + total);System.out.println("Time taken: " + (end - start) / 1.0e9);

}}

> java ConcurrentTotalFileSizeWLatch C:\Users\hpConcurrentTotalFileSizeWLatchTotal Size: 83625673020Time taken: 17.499908567

Start mit Root-Directory

Warten bis alle Tasks fertig!

> java ConcurrentTotalFileSizeWLatch C:\Users\hpConcurrentTotalFileSizeWLatchTotal Size: 83663127072Time taken: 12.961295139

aus: V. Subramaniam: Programming Concurrency on the JVM

Page 82: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 89

Beispiel Total File Size: Variante 4 (1/2)

TotalFile Size mit Queue mit Teilergebnissenpublic class ConcurrentTotalFileSizeWQueue {

private ExecutorService service;final private BlockingQueue<Long> fileSizes = new ArrayBlockingQueue<Long>(500);final AtomicLong pendingTasks = new AtomicLong();

private void startExploreDir(final File file) {pendingTasks.incrementAndGet();service.execute(new Runnable() {

public void run() {exploreDir(file);

}});

}private void exploreDir(final File file) {

long fileSize = 0;if (file.isFile())

fileSize = file.length();else {

final File[] children = file.listFiles();if (children != null)

for (final File child : children) {if (child.isFile())

fileSize += child.length();else

startExploreDir(child);}

}try {

fileSizes.put(fileSize);} catch (Exception ex) {

throw new RuntimeException(ex);}pendingTasks.decrementAndGet();

}...

Absetzen von Task pro FileRaufzählen von pendingTasks

Anfügen des Teilerbenisses in queue thread-safe

thread-safe Objekte

aus: V. Subramaniam: Programming Concurrency on the JVM

Page 83: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 90

Beispiel Total File Size: Variante 4 (2/2)

...private long getTotalSizeOfFile(final String fileName)

throws InterruptedException {service = Executors.newFixedThreadPool(100);try {

startExploreDir(new File(fileName));long totalSize = 0;while (pendingTasks.get() > 0 || fileSizes.size() > 0) {

final Long size = fileSizes.poll(10, TimeUnit.SECONDS);totalSize += size;

}return totalSize;

} finally {service.shutdown();

}}

public static void main(final String[] args) throws InterruptedException {final long start = System.nanoTime();final long total = new ConcurrentTotalFileSizeWQueue().getTotalSizeOfFile(args[0]);final long end = System.nanoTime();System.out.println("ConcurrentTotalFileSizeWQueue");System.out.println("Total Size: " + total);System.out.println("Time taken: " + (end - start) / 1.0e9);

}}

> java ConcurrentTotalFileSizeWQueue C:\Users\hpConcurrentTotalFileSizeWQueue Total Size: 83661507904Time taken: 13.3983663

Verarbeitung der Ergebnisse in der Queue!

> java ConcurrentTotalFileSizeWQueue C:\Users\hpConcurrentTotalFileSizeWQueueTotal Size: 83691338377Time taken: 10.754997324

aus: V. Subramaniam: Programming Concurrency on the JVM

Page 84: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 91

Beispiel Total File Size: Variante 5 (1/2)

TotalFile Size mit Fork-Join API

public class ForkJoinTotalFileSize {private final static ForkJoinPool forkJoinPool = new ForkJoinPool();

private static class FileSizeFinder extends RecursiveTask<Long> {final File file;public FileSizeFinder(final File theFile) {

file = theFile;}

@Overridepublic Long compute() {

long size = 0;if (file.isFile()) {

size = file.length();} else {

final File[] children = file.listFiles();if (children != null) {

List<ForkJoinTask<Long>> tasks = new ArrayList<ForkJoinTask<Long>>();for (final File child : children) {

if (child.isFile()) {size += child.length();

} else {tasks.add(new FileSizeFinder(child));

}}for (final ForkJoinTask<Long> task : invokeAll(tasks)) {

size += task.join();}

}}return size;

}}...

Absetzen von Subtask pro File:rekursiv !!

blockierendes Warten und Abholen des Ergebnisses

Task durch Ableiten von RecursiveTask<T>

Überschreiben von compute von RecursiveTask<T>

Erzeugen der Subtasks

Thread-Pool zur Ausführung der Tasks

aus: V. Subramaniam: Programming Concurrency on the JVM

Page 85: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 92

Beispiel Total File Size: Variante 5 (2/2)

...public static void main(final String[] args) {

final long start = System.nanoTime();final long total = forkJoinPool.invoke(new FileSizeFinder(new File(args[0])));final long end = System.nanoTime();System.out.println("ForkJoinTotalFileSize");System.out.println("Total Size: " + total);System.out.println("Time taken: " + (end - start) / 1.0e9);

}}

> java ForkJoinTotalFileSize C:\Users\hpForkJoinTotalFileSizeTotal Size: 83626897049Time taken: 13.98460454

Verfahren ähnlich wie Variante 1: rekursive Taskstruktur analog zur

rekursiven Directory-Struktur

Tasks werden bei Threads im Thread-Pool gequeued

„Work-Stealing“: Sobald ein Thread frei ist, übernimmt er Aufgaben von

anderen Threads

Ausführung des Root-Tasks durch Thread-Pool

> java ForkJoinTotalFileSize C:\Users\hpForkJoinTotalFileSizeTotal Size: 83663143456Time taken: 9.15555707

aus: V. Subramaniam: Programming Concurrency on the JVM

Page 86: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 93

Multithreading

Einleitung und Grundlagen

Multithreading Grundlagen

Probleme bei Multithreading

Klassisches Modell

Synchronisation

Threads und Swing

Neues Modell

Executors und Futures

Synchronisation

Concurrent Collections

Fallbeispiel

Zusammenfassung

Page 87: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 94

Zusammenfassung

Thread-safe = Programme, die auch bei Ausführung durch mehrere

Threads korrekt funktionieren

Problem ist gemeinsamer veränderlicher Speicher

Maßnahmen

kein (oder stark eingeschränkter) gemeinsamer veränderbarer Speicher

Ausführung bestimmer Teile in einem Thread (single thread rule)

synchronisierte Zugriffe

Gute Lösung oft: eingeschränkter gemeinsamer Speicher

und unveränderbare Datenstrukturen

Seit Verion 1.5 bei Java neues Threading-Konzept

Executors und ThreadPools

Futures und Callables

neue Synchronisationsmechanismen (Locks, Latch, ...)

Concurrent Collections

Wichtig bei hoch asynchronen Prozessen

Page 88: Java Database Connectivity-API (JDBC) · 2016. 4. 26. · Java Memory Model (JMM): Reihenfolge von Operationen und Sichtbarkeit von Daten Java Memory Model (JMM) definiert Bedingungen

SYSTEM SOFTWARE 95

Literatur

Doug Lea: Concurrent Programming in Java: Design Principles and Pattern

(2nd Edition) . A comprehensive work by a leading expert, who's also the

architect of the Java platform's concurrency framework.

Brian Goetz, Tim Peierls, Joshua Bloch, Joseph Bowbeer, David Holmes, and

Doug Lea: Java Concurrency in Practice. A practical guide designed to be

accessible to the novice.

Jeff Magee and Jeff Kramer: Concurrency: State Models & Java Programs

(2nd Edition). An introduction to concurrent programming through a

combination of modeling and practical examples.

Venkat Subramaniam: Programming Concurrency on the JVM. The Pragmatic

Bookshelf, 2011. Introduction to concurrency, software transactional

memory and actors in Java.