Wykład 9:
Programowanie Równoległe
●
oparte na procesach:
●
wykonywalny program
●
własna przestrzeń adresowa
●
droga komunikacja i zmiana kontekstu
●oparte na wątkach:
●
wątek to część programu
●
wspólna przestrzeń adresowa
Programowanie Równoległe w Javie
Oparte o wątki:
●
stany wątku: wykonywany, gotowy, zawieszony,
wznowiony, zablokowany
●
priorytety: wątek o wyższym priorytecie zawiesza ten
o niższym
●
synchronizacja: tylko jeden wątek wykonuje metodę
synchroniczną na danym obiekcie
Wątek Główny
●
tworzony automatycznie
●
wątek z którego powstają inne wątki
●pierwszy powstaje, ostatni kończy się
Uzyskanie odwołania do bieżącego wątku:
Wątek Główny: Przykład
class CurrentThreadDemo {public static void main(String args[]) { Thread t = Thread.currentThread();
System.out.println("Current thread: " + t); t.setName("My Thread");
System.out.println("After name change: " + t); try { for(int n = 5; n > 0; n--) { System.out.println(n); Thread.sleep(1000); } } catch (InterruptedException e) { System.out.println("Main interrupted"); } } }
Klasa Thread
Metody klasy
Thread
:
●
getName
– uzyskaj nazwę wątka
●
getPriority
– uzyskaj priorytet wątka
●isAlive
– czy wątek działa?
●
join
– czekaj na zakończenie wątka
●run
– wykonanie wątka
●
sleep
– zawieś wątek na jakiś czas
●start
– wystartuj wątek
Tworzenie Nowego Wątka
●
przez implementację interfejsu
Runnable
●przez dziedziczenie po klasie
Thread
Kiedy który?
●
wśród metod
Thread
, tylko
run()
musi być
przesłonięty
●
wybierz dziedziczenie po
Thread
, gdy inne metody
Tworzenie Nowego Wątka: Runnable
class NewThread implements Runnable {Thread t;
NewThread() {
t = new Thread(this, "Demo Thread");
System.out.println("Child thread: " + t); t.start(); // Start the thread
}
public void run() { try {
for(int i = 5; i > 0; i--) {
System.out.println("Child Thread: " + i); Thread.sleep(500);
}
} catch (InterruptedException e) {
System.out.println("Child interrupted."); }
Tworzenie Nowego Wątka: Runnable
System.out.println("Exiting child thread."); }}
class ThreadDemo {
public static void main(String args[]) { new NewThread(); // create a new thread try {
for(int i = 5; i > 0; i--) {
System.out.println("Main Thread: " + i); Thread.sleep(1000);
}
} catch (InterruptedException e) {
System.out.println("Main interrupted."); }
System.out.println("Main thread exiting."); }
Tworzenie Nowego Wątka: Thread
class NewThread extends Thread {NewThread() {
super("Demo Thread");
System.out.println("Child thread: " + this); start(); // Start the thread
}
public void run() { try {
for(int i = 5; i > 0; i--) {
System.out.println("Child Thread: " + i); Thread.sleep(500);
}
} catch (InterruptedException e) {
System.out.println("Child interrupted."); }
Tworzenie Nowego Wątka: Thread
System.out.println("Exiting child thread."); }
}
class ExtendThread {
public static void main(String args[]) { new NewThread(); // create a new thread try {
for(int i = 5; i > 0; i--) {
System.out.println("Main Thread: " + i); Thread.sleep(1000);
}
} catch (InterruptedException e) {
System.out.println("Main interrupted."); }
System.out.println("Main thread exiting."); }
Wiele Wątków: Przykład 1
class NewThread implements Runnable { String name; // name of thread
Thread t;
NewThread(String threadname) { name = threadname;
t = new Thread(this, name);
System.out.println("New thread: " + t); t.start(); // Start the thread
Wiele Wątków: Przykład 2
// This is the entry point for thread. public void run() {
try { for(int i = 5; i > 0; i--) { System.out.println(name + ": " + i); Thread.sleep(1000); } } catch (InterruptedException e) { System.out.println(name + "Interrupted"); } System.out.println(name + " exiting."); } }
Wiele Wątków: Przykład 3
class MultiThreadDemo {public static void main(String args[]) { new NewThread("One"); // start threads new NewThread("Two");
new NewThread("Three"); try {
// wait for other threads to end Thread.sleep(10000);
} catch (InterruptedException e) {
System.out.println("Main Interrupted"); }
System.out.println("Main thread exiting."); }
Zakończenie Wątku
Metoda zwraca true, jeśli wątek na której jest
wywołana wykonuje się:
final boolean isAlive()
Metoda czeka aż wątek na której wykonuje się
zakończy się:
Zakończenie Wątku: Przykład 1
class NewThread implements Runnable {String name; // name of thread Thread t;
NewThread(String threadname) { name = threadname;
t = new Thread(this, name);
System.out.println("New thread: " + t); t.start(); // Start the thread
Zakończenie Wątku: Przykład 2
// This is the entry point for thread. public void run() {try { for(int i = 5; i > 0; i--) { System.out.println(name + ": " + i); Thread.sleep(1000); } } catch (InterruptedException e) { System.out.println(name + " interrupted."); } System.out.println(name + " exiting."); } }
Zakończenie Wątku: Przykład 3
class DemoJoin {public static void main(String args[]) { NewThread ob1 = new NewThread("One"); NewThread ob2 = new NewThread("Two"); NewThread ob3 = new NewThread("Three"); System.out.println(ob1.t.isAlive());
System.out.println(ob2.t.isAlive()); System.out.println(ob3.t.isAlive()); // wait for threads to finish
try { System.out.println("Waiting to finish."); ob1.t.join(); ob2.t.join(); ob3.t.join(); } catch (InterruptedException e) { System.out.println("Main Interrupted"); }
Zakończenie Wątku: Przykład 3
System.out.println(ob1.t.isAlive()); System.out.println(ob2.t.isAlive()); System.out.println(ob3.t.isAlive());System.out.println("Main thread exiting."); }
Priorytet Wątku
Decyduje kiedy wątek może się wykonywać.
W praktyce, czas CPU poświęcony dla wątku zależy od
szeregu innych czynników.
Ustalenie i sprawdzenie priorytetu:
final void setPriority(int level)
final int getPriority()
final int MIN_PRIORITY = 1
final int MAX_PRIORITY = 10
final int NORM_PRIORITY = 5
Priorytet Wątku: Przykład 1
class clicker implements Runnable { int click = 0;Thread t;
Zapewnia że
running
jest sprawdzane w każdej
iteracji pętli, inaczej pętla może być optymalizowana.
Priorytet Wątku: Przykład 2
public clicker(int p) {t = new Thread(this); t.setPriority(p);
}
public void run() {
while (running) { click++; } }
public void stop() { running = false; } public void start() { t.start(); }
Priorytet Wątku: Przykład 3
class HiLoPri {public static void main(String args[]) { Thread.currentThread(). setPriority(Thread.MAX_PRIORITY); clicker hi = new clicker(Thread.NORM_PRIORITY+2); clicker lo = new clicker(Thread.NORM_PRIORITY – 2); lo.start(); hi.start(); try { Thread.sleep(10000); } catch (InterruptedException e) { System.out.println("Main interrupted."); }
Priorytet Wątku: Przykład 4
lo.stop();hi.stop();
// Wait for child threads to terminate. try { hi.t.join(); lo.t.join(); } catch (InterruptedException e) { System.out.println( "InterruptedException caught"); } System.out.println("Low: " + lo.click); System.out.println("High: " + hi.click); } }
Synchronizacja Wątków
Kiedy kilka wątków korzysta z dzielonych zasobów.
Jak zapewnić aby tylko jeden wątek używał ten zasób.
Monitor: obiekt do którego może wejść jeden wątek.
Dwie metody:
●
użycie metod
synchronized
Metody Synchronized
Każdy obiekt ma związany z nim monitor.
Aby wejść do monitora, wywołaj jedną z metod
oznaczonych jako
synchronized
.
W tym czasie, wszystkie wątki muszą czekać aby
wykonać metodę
synchronized
na tym obiekcie.
Aby wyjść z monitora, wątek musi wyjść z metody
Metody Synchronized: Przykład 1
class Callme { void call(String msg) { System.out.print("[" + msg); try { Thread.sleep(1000); } catch(InterruptedException e) { System.out.println("Interrupted"); } System.out.println("]"); } }Metody Synchronized: Przykład 2
class Caller implements Runnable {String msg;
Callme target; Thread t;
public Caller(Callme targ, String s) { target = targ;
msg = s;
t = new Thread(this); t.start();
}
public void run() { target.call(msg); }
}
class Synch {
public static void main(String args[]) { Callme target = new Callme();
Caller ob1 = new Caller(target, "Hello"); Caller ob2 = new Caller(target,
"Synchronized");
Caller ob3 = new Caller(target, "World"); // wait for threads to end
try { ob1.t.join(); ob2.t.join(); ob3.t.join(); } catch(InterruptedException e) { System.out.println("Interrupted"); } } }
Metody Synchronized: Przykład 3
public static void main(String args[]) { Callme target = new Callme();Caller ob1 = new Caller(target, "Hello"); Caller ob2 = new Caller(target, "Synch");
Caller ob3 = new Caller(target, "World"); // wait for threads to end
try { ob1.t.join(); ob2.t.join(); ob3.t.join(); } catch(InterruptedException e) { System.out.println("Interrupted"); } } }
Metody Synchronized
Trzy wywołania metody call przeplatają się w czasie.
Należy zapewnić serializację wykonania call:
class CallMe {
synchronized void call(Sting msg) { ...
} }
To zapobiegnie aby inne wątki wykonywały metodę
Instrukcja Synchronized
Synchronizacja dostępu do klasy która nie była
zaprojektowana dla wielo-wątkowości.
synchronized(object) { ...
}
Zapewnia że wywołanie metody składowej obiektu
Instrukcja Synchronized: Przykład 1
class Callme { void call(String msg) { System.out.print("[" + msg); try { Thread.sleep(1000); } catch (InterruptedException e) { System.out.println("Interrupted"); } System.out.println("]"); } }Instrukcja Synchronized: Przykład 2
class Caller implements Runnable {String msg;
Callme target; Thread t;
public Caller(Callme targ, String s) { target = targ;
msg = s;
t = new Thread(this); t.start();
}
public void run() {
synchronized(target) { target.call(msg);
} } }
Instrukcja Synchronized: Przykład 3
class Synch1 {public static void main(String args[]) { Callme target = new Callme();
Caller ob1 = new Caller(target, "Hello"); Caller ob2 = new Caller(target, "Synch"); Caller ob3 = new Caller(target, "World"); // wait for threads to end
try { ob1.t.join(); ob2.t.join(); ob3.t.join(); } catch(InterruptedException e) { System.out.println("Interrupted"); } } }
Instrukcja Synchronized: Przykład 3
String msg;Callme target; Thread t;
public Caller(Callme targ, String s) { target = targ;
msg = s;
t = new Thread(this); t.start();
}
// synchronize calls to call() public void run() {
synchronized(target) { // synchronized block target.call(msg);
} } }
class Synch1 {
public static void main(String args[]) { Callme target = new Callme();
Caller ob1 = new Caller(target, "Hello"); Caller ob2 = new Caller(target,
"Synchronized");
Caller ob3 = new Caller(target, "World"); // wait for threads to end
try { ob1.t.join(); ob2.t.join(); ob3.t.join(); } catch(InterruptedException e) { System.out.println("Interrupted"); } } }