Wykład 9: Programowanie Wielo
Transkrypt
Wykład 9: Programowanie Wielo
Wykład 9: Programowanie Wielo-Wątkowe 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 ● tania komunikacja i zmiana kontekstu ● 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 ● komunikacja: przez metody synchroniczne ● 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: static Thread currentThread() 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 muszą być przesłonięte ● 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ę: final void join() throws InterruptedException 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 final final final final void setPriority(int level) int getPriority() int MIN_PRIORITY = 1 int MAX_PRIORITY = 10 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. private volatile boolean running = true; 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 ● użycie instrukcji 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 synchronized. 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); } 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ę call w czasie gdy inny wątek ją wykonuje. 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 wykona się tylko po wejściu do monitora tego 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); }