Programowanie sieciowe w Javie Michał Kuciapski
Wątki
Koncepcja i tworzenie
4 z 53 Definicja Wątek (ang. thread) jest pojedynczą ścieżką wykonywania (przepływem sterowania) wykonywaną oddzielnie i niezależnie. Każdy wątek ma początek, sekwencje instrukcji i koniec. Relacja pomiędzy wątkami określana głównie poprzez dwa mechanizmy: synchronizację i zasadę pierwszeństwa (priorytet).
5 z 53 Koncepcja Wątki umożliwiają podział zadań (programów) na mniejsze funkcjonalnie spójne fragmenty kodu wykonywanego (odseparowane strumienie wykonywania działań). Tworzenie wielu wątków umożliwia równoczesne wykonywanie zadań - programowanie równoległe, programowanie współbieżne. Ma to na celu: tworzenie aplikacji asynchronicznych, zwiększenia efektywności działania oraz ma charakter porządkowania kodu. Każdy program może składać się z wątków dla wydzielenia poszczególnych zadań. Wirtualna Maszyna Javy posiada wiele wątków jak np.: obsługujący kod z metod main(), obsługuję zarządzanie pamięcią (GarbageCollection), odświeżanie ekranu.
6 z 53 Tworzenie wątków W Javie wątki są obiektami zdefiniowanymi za pomocą specjalnego rodzaju klas. Tworzone są: Jako podklasa klasy Thread Poprzez implementacje interfejsu Runnable I następnie uruchamiane poprzez polecenie start(). Tak jak w programie sekwencyjnym, każdy wątek ma swoje zarezerwowane zasoby i może korzystać z zasobów programu, w którym jest wykonywany.
7 z 53 Tworzenie wątków – sposoby - przykład Dla metody dziedziczenia Thread watek = new MojaKlasaWatek(parametr); watek.start(); Dla implementacji interfejsu Runnable KlasaRunnable wRunnable = new KlasaRunnable(parametr); Thread watek = new Thread(wRunnable); watek.start();
8 z 53 Podstawowe metody wątków start() - jawnie wywołuje rozpoczęcie wątku run() - zawiera zestaw zadań do wykonania. Metoda ta nie jest wywoływana jawnie lecz pośrednio poprzez metodę start() powodującą wykonanie działań zawartych w definicji metody run(). Jeśli w międzyczasie nie zostanie przerwane zadanie, w ciele którego dany wątek działa, to końcem życia wątku będzie koniec działania metody run()
9 z 53 Podstawowe metody wątków c.d. static int activeCount() - powoduje zwrócenie liczby wszystkich aktywnych wątków danej grupy static int enumerate(Thread[] tablicaWatkow) - powoduje skopiowanie wszystkich aktywnych wątków danej grupy do tablicy oraz powoduje zwrócenie liczby wszystkich skopiowanych wątków static currentThread() – zwraca referencje do aktualnie wykonywanego wątku
10 z 53 Podstawowe metody wątków c.d. static yield() - powoduje czasowe przerwanie wykonywania aktualnego wątku dla wykonywania innych wątków static void sleep (long czasWstrzymania) – powoduje uśpienie działania wątku na okres w milisekundach void join() - czeka na skończenie się wątku void destroy() – niszczy wątek void setName(String nazwa) – ustawia nazwę wątku String getName() - zwraca nazwę wątku void setPriority(int priorytet) – zmienia priorytet wątku void getPriority() - zwraca priorytet wątku void isAlive() – sprawdza czy wątek istnieje
11 z 53 Wątek – przykład 1 class Watek extends Thread { private String tekst; public Watek(String nazwaWatek, String parTekst) { super(nazwaWatek); tekst = parTekst; } public void run() { for (int i = 0; i < 4; i++) { System.out.println(i + ": " + getName() + " - " + tekst); try{ sleep( (int)(Math.random() * 5000) );} catch (InterruptedException e ) { e.printStackTrace();} } System.out.println(getName() + " - koniec wątku" ); }
12 z 53 Wątek – przykład 1 c.d. public class WatkiDziedziczenie{ public static void main(String args[]) { System.out.println("Program pokazujący działanie wątków " + "tworzonych poprzez dziedziczenie klasy Thread \n"); Thread watekSystem1 = new Watek("Active directory", "Uruchomienie usługi Active Directory"); Thread watekSystem2 = new Watek("Ustawienia sieciowe", "Implementacja ustawień sieciowych"); Thread watekSystem3 = new Watek("Polisy grupowe", "Implementacja polis grupowych"); Thread watekSystem4 = new Watek("System", "Uruchomienie systemu"); watekSystem1.start(); watekSystem2.start(); watekSystem3.start(); watekSystem4.start(); }
13 z 53 Wątek – przykład 2 class Watek implements Runnable { private String tekst; private Thread watekBiezacy = new Thread(); public Watek(String nazwaWatek, String parTekst) { watekBiezacy = Thread.currentThread(); //watekBiezacy.setName(nazwaWatek); watekBiezacy = new Thread(nazwaWatek); tekst = parTekst; } public void run() {
14 z 53 Wątek – przykład 1 c.d. for (int i = 0; i < 4; i++) { System.out.println(i + ": " + watekBiezacy.getName() + " - " + tekst); try { watekBiezacy.sleep( (int)(Math.random() * 5000) ); } catch ( InterruptedException e ) { e.printStackTrace(); } System.out.println(watekBiezacy.getName() + " - koniec wątku" ); }
15 z 53 Wątek – przykład 1 c.d. public class WatkiRunnable{ public static void main(String args[]) { System.out.println("Program pokazujący działanie wątków " + "tworzonych poprzez implementowanie interfejsu Runnable \n"); Thread watekSystem1 = new Thread(new Watek("Active directory", "Uruchomienie usługi Active Directory")); Thread watekSystem2 = new Thread(new Watek("Ustawienia sieciowe", "Implementacja ustawień sieciowych")); Thread watekSystem3 = new Thread(new Watek("Polisy grupowe", "Implementacja polis grupowych")); Thread watekSystem4 = new Thread(new Watek("System", "Uruchomienie systemu")); watekSystem1.start(); watekSystem2.start(); watekSystem3.start(); watekSystem4.start(); } }
16 z 53 Stany wątku
Wątki Synchronizacja
18 z 53 Koncepcja Synchronizacja umożliwia zarządzanie dostępem do zasobów poprzez przydzielanie ich na zasadzie okresowego zablokowania określonemu wątkowi. Synchronizacja pozwala na zapewnienie kolejności wykonywania poszczególnych zależnych od siebie czynności programu. Problemami z nią związanymi są: –konieczność czekania przez inne wątki na zakończenie korzystania z synchronizowanego zasobu –ryzyko wystąpienia zakleszczenia, polegającego na wzajemnym blokowaniu siebie wątków
19 z 53 Metody Można wyróżnić 3 metody synchronizacji: –bloku –samego obiektu –metody Writter out; synchronized (out) { Calendar teraz = Calendar.getInstance(); out.write(teraz.get(Calendar.HOUR_OF_DAY)); out.write( „\r\n" ); } Synchronized (this) Synchronized void zapiszLog() throws IOException
20 z 53 Zakleszczenie Pojawia się w sytuacji gdy każdy z dwóch wątków wymaga wyłącznego dostępu do tego samego zestawu zasobów, ale każdy posiada jego inny element. Techniki unikania zakleszczenia: Ograniczanie synchronizacji Synchronizowanie jak najmniejszych bloków kodu Unikanie synchronizowania na więcej niż jednym obiekcie Wykorzystywanie lokalnych kopii obiektów Analizowanie klas, które wykorzystują klika synchronizowanych obiektów
Wątki Informacje zwrotne, priorytety
22 z 53 Informacje zwrotne W sytuacji, gdy wykonywany kod, wątek lub proces zależy od wyniku działania lub stanu innego wątku niezbędne konieczne jest uzyskanie od niego informacji zwrotnych. Metody uzyskiwania informacji: odpytywanie – okresowo sprawdzana jest flaga wątku wywołania zwrotne – wątek powiadamia program główny
23 z 53 Priorytety Analogicznie jak procesom systemowym, wątkom w zależności od ważności można przypisywać priorytety, określając przydzielony czas. Dla priorytetów zdefiniowane są 3 stałe: –MIN_PRIORITY = 1 –NORM_PRIORITY = 5 –MAX PRIORYTY = 10
24 z 53 Przykład class Opcja implements Runnable { String tekst; Thread watek; Opcja(String tytul, String parTekst) { watek = new Thread(tytul); tekst = parTekst; } public void run() { for(int i=0; i<=3; i++) { try { Thread.currentThread().sleep((int)(Math.random() * 5000)); System.out.println(watek.getName() + " mówi: " + tekst); WczesniejszeWyboryRunnableWywolanieZwrotne.ostatniaOpcja(tekst); } catch(InterruptedException e) { System.out.println("Nastąpił błąd: " + e.getMessage()); } } } }
25 z 53 Przykład c.d. public class WczesniejszeWyboryRunnableWywolanieZwrotnePriorytety { static String ostatniaOpcja; public static void ostatniaOpcja(String tekst) { ostatniaOpcja = tekst; } public static void main(String args[]) { System.out.println("Symulacja scenariuszy odnośnie wcześniejszych wyborów :-)"); Opcja lepper = new Opcja("Andrzej Lepper", "Koalicja"); Opcja kaczor = new Opcja("Jarosław Kaczyński", "Wcześniejsze wybory"); Opcja donald = new Opcja("Donald tusk", "Wszystko tylko nie wcześniejsze wybory"); Opcja analitycy = new Opcja("Analityk giełdowy", "Rząd mniejszościowy"); Thread lepperT = new Thread(lepper); Thread kaczorT = new Thread(kaczor); Thread donaldT = new Thread(donald); Thread analitycyT = new Thread(analitycy); lepperT.setPriority(1); kaczorT.setPriority(2); donaldT.setPriority(3); analitycyT.setPriority(4);
26 z 53 Przykład c.d. lepperT.start(); kaczorT.start(); donaldT.start(); analitycyT.start(); try { lepperT.join(); kaczorT.join(); donaldT.join(); analitycyT.join(); } catch(InterruptedException e) { System.out.println("Nastąpił błąd: " + e.getMessage()); }
Wątki Przykład zastosowania sieciowego