6.1 Pojęcie wątku programu 6.2 Klasy Timer, TimerTask 6.3 Klasa Thread 6.4 Synchronizacja pracy wątków 6.5 Grupowanie wątków



Podobne dokumenty
Współbieżność w środowisku Java

Język Java wątki (streszczenie)

Wątki. Definiowanie wątków jako klas potomnych Thread. Nadpisanie metody run().

Język Java wątki (streszczenie)

Wielowątkowość. Programowanie w środowisku rozproszonym. Wykład 1.

Współbieżność i równoległość w środowiskach obiektowych. Krzysztof Banaś Obliczenia równoległe 1

Autor: dr inż. Zofia Kruczkiewicz, Programowanie aplikacji internetowych 1

Kurs programowania. Wykład 8. Wojciech Macyna. 10 maj 2017

Wątek - definicja. Wykorzystanie kilku rdzeni procesora jednocześnie Zrównoleglenie obliczeń Jednoczesna obsługa ekranu i procesu obliczeniowego

Kurs programowania. Wykład 8. Wojciech Macyna

Współbieżność w Javie

Obliczenia równoległe i rozproszone w JAVIE. Michał Kozłowski 30 listopada 2003

Java. Wykład. Dariusz Wardowski, Katedra Analizy Nieliniowej, WMiI UŁ

Języki i Techniki Programowania II. Wykład 7. Współbieżność 1

1 Wątki 1. 2 Tworzenie wątków 1. 3 Synchronizacja 3. 4 Dodatki 3. 5 Algorytmy sortowania 4

Współbieżność w Javie

W Javie wątki są obiektami zdefiniowanymi za pomocą specjalnego rodzaju klas.

Wątki w Javie. Piotr Tokarski

Aplikacje w Javie- wykład 11 Wątki-podstawy

Podstawy współbieżności

Wielowątkowość mgr Tomasz Xięski, Instytut Informatyki, Uniwersytet Śląski Katowice, 2011

Programowanie wielowątkowe. Tomasz Borzyszkowski

Programowanie współbieżne i rozproszone

Programowanie równoległe i rozproszone. Monitory i zmienne warunku. Krzysztof Banaś Programowanie równoległe i rozproszone 1

Programowanie równoległe i rozproszone. W1. Wielowątkowość. Krzysztof Banaś Programowanie równoległe i rozproszone 1

Programowanie komputerów

Programowanie wielowątkowe: podstawowe koncepcje, narzędzia w Javie. J. Starzyński, JiMP2, rok akad. 2005/2006

4.1 Napisz kod, w którym definiujesz, tworzysz oraz uruchamiasz wątki z uŝyciem klas java.lang.thread oraz java.lang.runnable.

WSPÓŁBIEŻNOŚĆ. MATERIAŁY:

Programowanie w Sieci Internet. Python: Wątki. Kraków, 12 grudnia 2014 r. mgr Piotr Rytko Wydział Matematyki i Informatyki

Java. Programowanie Obiektowe Mateusz Cicheński

Multimedia JAVA. Historia

Stworzenie klasy nie jest równoznaczne z wykorzystaniem wielowątkowości. Uzyskuje się ją dopiero poprzez inicjalizację wątku.

Semafor nie jest mechanizmem strukturalnym. Aplikacje pisane z użyciem semaforów są podatne na błędy. Np. brak operacji sem_post blokuje aplikację.

Programowanie współbieżne Laboratorium nr 11

Współbieżność i równoległość w środowiskach obiektowych. Krzysztof Banaś Obliczenia równoległe 1

Przetwarzanie równoległe i współbieżne

Interfejsy w Java. Przetwarzanie równoległe. Wątki.

Programowanie obiektowe. Literatura: Autor: dr inŝ. Zofia Kruczkiewicz

Wątki (Threads) Potrzeby. Przetwarzanie równoległe i współbieŝne. Cechy programowania wątkowego. Concurrent programming is like

Programowanie współbieżne Wykład 5. Rafał Skinderowicz

Semafor nie jest mechanizmem strukturalnym. Aplikacje pisane z użyciem semaforów są podatne na błędy. Np. brak operacji sem_post blokuje aplikację.

Programowanie obiektowe zastosowanie języka Java SE

Dokumentacja do API Javy.

Język JAVA podstawy. Wykład 3, część 3. Jacek Rumiński. Politechnika Gdańska, Inżynieria Biomedyczna

JAVA W SUPER EXPRESOWEJ PIGUŁCE

Język JAVA podstawy. wykład 2, część 2. Jacek Rumiński. Politechnika Gdańska, Inżynieria Biomedyczna

Systemy Rozproszone - Ćwiczenie 4

Równolegªo± w Javie w tki.

1 Atrybuty i metody klasowe

Programowanie obiektowe

Wykład 8: Obsługa Wyjątków

Klasy abstrakcyjne i interfejsy

Kurs programowania. Wykład 2. Wojciech Macyna. 17 marca 2016

Kurs programowania. Wykład 6. Wojciech Macyna. 7 kwietnia 2016

Aplikacje Internetowe. Najprostsza aplikacja. Komponenty Javy. Podstawy języka Java

Monitory. Jarosław Kuchta

Programowanie obiektowe

Programowanie współbieżne Wykład 2. Rafał Skinderowicz

Java: kilka brakujących szczegółów i uniwersalna nadklasa Object

Obszar statyczny dane dostępne w dowolnym momencie podczas pracy programu (wprowadzone słowem kluczowym static),

Programowanie obiektowe i zdarzeniowe wykład 4 Kompozycja, kolekcje, wiązanie danych

Operatory. Składnia. Typy proste. Znaki specjalne

Java: otwórz okienko. Programowanie w językach wysokiego poziomu. mgr inż. Anna Wawszczak

dziedziczenie - po nazwie klasy wystąpią słowa: extends nazwa_superklasy

7 Pewne uzupełnienia Przepływ sterowania Układacze... 6

Metody Metody, parametry, zwracanie wartości

Wykład 5. Synchronizacja (część II) Wojciech Kwedlo, Wykład z Systemów Operacyjnych -1- Wydział Informatyki PB

Konstruktory. Streszczenie Celem wykładu jest zaprezentowanie konstruktorów w Javie, syntaktyki oraz zalet ich stosowania. Czas wykładu 45 minut.

Języki i metody programowania Java INF302W Wykład 2 (część 1)

Obiektowe programowanie rozproszone Java RMI. Krzysztof Banaś Systemy rozproszone 1

Programowanie obiektowe

Programowanie obiektowe

Wyjątki. Streszczenie Celem wykładu jest omówienie tematyki wyjątków w Javie. Czas wykładu 45 minut.

UML a kod w C++ i Javie. Przypadki użycia. Diagramy klas. Klasy użytkowników i wykorzystywane funkcje. Związki pomiędzy przypadkami.

Systemy operacyjne. Zajęcia 11. Monitory

Programowanie współbieżne Wykład 10 Synchronizacja dostępu do współdzielonych zasobów. Iwona Kochańska

Interfejsy. Programowanie obiektowe. Paweł Rogaliński Instytut Informatyki, Automatyki i Robotyki Politechniki Wrocławskiej

Java - wprowadzenie. Programowanie Obiektowe Mateusz Cicheński

Aplikacja wielowątkowa prosty komunikator

Programowanie współbieżne Laboratorium nr 12

Wykład 7: Pakiety i Interfejsy

Wykład 6: Dziedziczenie

Laboratorium z przedmiotu: Inżynieria Oprogramowania INEK Instrukcja 7

Enkapsulacja, dziedziczenie, polimorfizm

Wywoływanie metod zdalnych

Kurs programowania. Wykład 9. Wojciech Macyna. 28 kwiecień 2016

WIELOWĄTKOWOŚĆ. Waldemar Korłub. Platformy Technologiczne KASK ETI Politechnika Gdańska

Programowanie w Internecie. Java

Projektowanie aplikacji internetowych laboratorium

Generatory. Michał R. Przybyłek

Programowanie w języku Java - Wyjątki, obsługa wyjątków, generowanie wyjątków

Języki i metody programowania Java. Wykład 2 (część 2)

TEMAT : KLASY DZIEDZICZENIE

PHP 5 język obiektowy

JAVA. Java jest wszechstronnym językiem programowania, zorientowanym. apletów oraz samodzielnych aplikacji.

1. Co będzie wynikiem wykonania poniŝszych instrukcji? g2d.gettransform().scale(1, -1); g2d.gettransform().translate(4, -8); g2d.drawline(4, 0, 4, 4);

Programowanie obiektowe

Polimorfizm, metody wirtualne i klasy abstrakcyjne

11.6 Klasa do obsługi liczb wymiernych

Transkrypt:

6. Wątki 6.1 Pojęcie wątku programu 6.2 Klasy Timer, TimerTask 6.3 Klasa Thread 6.4 Synchronizacja pracy wątków 6.5 Grupowanie wątków W. Kasprzak: Programowanie zdarzeniowe 6-1 6.1 Wątki programu 1) Pojęcie wątku Wątek ("thread") to osobna sekwencja wykonania instrukcji programu w ramach jednego programu, wykonywana współbieŝnie z innymi wątkami tego programu. W odróŝnieniu od procesu wątek posiada jedynie swój kontekst wykonania stos, rejestry i licznik rozkazów ale współdzieli on pamięć dynamiczną ( stertę ) programu z innymi wątkami tego programu. Wątki znajdują zastosowanie tam, gdzie rozwiązanie zadania moŝe być zrealizowane przez algorytm równoległy. Przykłady zadań dla wątków: obliczenie liczb pierwszych, sortowanie danych, wykonywanie animacji, itp. Dzięki wątkom realizujemy mechanizm asynchronicznego wywoływania i wykonywania metod w ramach jednego programu. W. Kasprzak: Programowanie zdarzeniowe 6-2

6.2 Klasy Timer i TimerTask Klasy java.util.timer (extends Object) i TimerTask (extends Object implements Runnable) są poŝyteczne do wyznaczania czasu wznowienia wątku po pewnej przerwie. Uwaga: dla programu posiadającego GUI realizowany w Swing-u odpowiednią klasą jest javax.swing.timer zamiast java.util.timer. Metody klasy Timer przeznaczone do wybierania zadań: // Wykonanie zadania po upływie czasu lub o dokładnej porze: schedule (TimerTask task, long delay) schedule (TimerTask task, Date time) // Wielokrotne wznawianie wykonania co okres czasu: // - "miękkie" dotrzymanie okresu gdy poprzednie wykonanie się zakończyło schedule (TimerTask task, long delay, long okres) schedule (TimerTask task, Date time, long okres) //- ustalony na sztywno okres bez względu na zakończenie poprzedniego scheduleatfixedrate (TimerTask task, long delay, long okres) scheduleatfixedrate (TimerTask task, Date firsttime, long okres) W. Kasprzak: Programowanie zdarzeniowe 6-3 Jednokrotne asynchroniczne wykonanie zadania po upływie czasu Przykład. Zastosujemy klasy Timer i TimerTask dla asynchronicznego wykonania zadania po upływie 5 sekund. import java.util.timer; import java.util.timertask; public class Przypomnienie { // Klasa główna naszego zadania Timer timer; public Przypomnienie(int sekundy) { // Konstruktor klasy głównej timer = new Timer(); // (3) Tworzymy wątek - obiekt klasy Timer timer.schedule(new PrzypomTimerTask(), sekundy*1000); // (4) // (4) Tworzymy obiekt naszego typu pochodnego od TimerTask i // wybieramy go do wykonania po upływie 5000 ms // W klasie głównej definiujemy klasę wewnętrzną - // (1) definiujemy własną klasę pochodną po TimerTask: class PrzypomTimerTask extends TimerTask { public void run() { // (2) Metoda run() wykonuje zadanie wątku W. Kasprzak: Programowanie zdarzeniowe 6-4

System.out.println("Czas minął!"); timer.cancel(); // Zakończ wątek obiekt timer public static void main(string args[]) { // Metoda main() klasy głównej System.out.println("Wybieranie zadania."); new Przypomnienie(5); // Konstrukcja obiektu klasy głównej System.out.println("Zadanie wybrane."); Wynik: Zadanie wybrane. Czas minął Drugi napis pojawi się po 5 sekundach po pierwszym. W. Kasprzak: Programowanie zdarzeniowe 6-5 Jednokrotne asynchroniczne wykonanie zadania o określonej porze Przykład. Wykonanie zadania o godzinie 23:01. W treści konstruktora naszej klasy Przypomnienie : public Przypomnienie(int sekundy) { // Pobierz dzisiejszą datę Calendar calendar = Calendar.getInstance(); calendar.set(calendar.hour_of_day, 23); // Ustaw godzinę calendar.set(calendar.minute, 1); calendar.set(calendar.second, 0); Date time = calendar.gettime(); timer = new Timer(); // Utwórz wątek nadzorujący czas // Wykonaj wątek zadania o podanej godzinie tego dnia: timer.schedule( new PrzypomTimerTask(), time); W. Kasprzak: Programowanie zdarzeniowe 6-6

Zatrzymanie wątków klasy Timer jest moŝliwe na 4 sposoby: 1. wywołanie metody cancel() dla obiektu klasy Timer (jak powyŝej); 2. utworzyć wątek - demon wywołaniem konstruktora: new Timer(true) ; program którego jedynymi wątkami pozostały wątki demony zakończy się (w podanych przykładach nie moŝna tak postąpić, gdyŝ czekamy na wykonanie się zadania zleconego przez obiekt klasy Timer); 3. usunąć wszystkie referencje do obiektu klasy Timer, moŝe to zakończyć wątek obiektu Timer-a. 4. wywołanie metody System.exit zakończy cały program - w tym jego wątki. Przykład. Dodanie do klasy Przypomnienie dzwonka i wywołanie metody System.exit w celu zakończenia programu. public class PrzypomnienieDzwonkiem {... public PrzypomnienieDzwonkiem (int sekundy) { W. Kasprzak: Programowanie zdarzeniowe 6-7 toolkit = Toolkit.getDefaultToolkit(); // W celu uzyskania dzwonka timer = new Timer(); timer.schedule(new PrzypomTimerTask(), sekundy*1000); // Klasa dla zadania wątku class PrzypomTimerTask extends TimerTask { public void run() { System.out.println(Czas minął!"); toolkit.beep(); //timer.cancel(); // Teraz niepotrzebne, gdyŝ wołamy System.exit System.exit(0); // Zatrzyma wątek główny programu (i inne)... W. Kasprzak: Programowanie zdarzeniowe 6-8

Wielokrotne, cykliczne wykonywanie zadania Przykład. Wybieramy wykonanie zadania cyklicznie raz na sekundę. public class DenerwujacyDzwonek { Toolkit toolkit; Timer timer; public DenerwujacyDzwonek () { toolkit = Toolkit.getDefaultToolkit(); timer = new Timer(); timer.schedule(new PrzypomTimerTask(), 0, // początkowe oczekiwanie 1*1000); // cyklicznie co okres czasu 1 sekundy class PrzypomTimerTask extends TimerTask { int liczbadzwonkow = 3; public void run() { if (liczbadzwonkow!= 0) { toolkit.beep(); W. Kasprzak: Programowanie zdarzeniowe 6-9... System.out.println("Dzwoni!"); liczbadzwonkow--; else { toolkit.beep(); System.out.println("Czas minął!"); //timer.cancel(); //Niepotrzebne - wołamy System.exit System.exit(0); // Zatrzyma wątek główny (i inne) Wynik wykonania: Zadanie wybrane. Dzwoni! Dzwoni! // 1 sekunda po 1-szym "Dzwoni" Dzwoni! // 1 sekunda po 2-im "Dzwoni" Czas minął! // 1 sekunda po 3-im "Dzwoni" W. Kasprzak: Programowanie zdarzeniowe 6-10

6.3 Klasa Thread Bazowa klasa wątków to java.lang.thread - wprowadza m.in. metody: start() rozpoczyna wykonywanie treści wątku zdefiniowanej w run() stop(), stop(throwable obj); - (metody niezabezpieczone) zamiast nich naleŝy sprawdzać warunek w run() i zakończyć odpowiednio tę metodę; sleep(long millis), sleep(long millis, int nanos) uśpienie wątku na pewien czas; yield() czasowo zatrzymuje wątek i ustawia go na końcu kolejki; getpriority(), setpriority(int) pobierze i ustawi priorytet wątku. 1) Metoda run() Implementacja wątku opartego na klasie Thread wymaga zdefiniowania metody void run() - zawera ona zadanie wykonywane przez wątek. Klasa Thread zawiera definicję metody run() o pustym kodzie. W. Kasprzak: Programowanie zdarzeniowe 6-11 Klasy mogą tworzyć metody run() na dwa sposoby: 1. przez dziedziczenie po klasie Thread i nadpisanie metody run(); 2. przez implementację interfejsu Runnable - wtedy klasa musi zawierać implementację metody run(). Dziedziczenie po klasie Thread i nadpisanie run() - klasa Thread juŝ implementuje Runnable. Przykład. Klasa ProstyWatek (implementuje wątek) i klasa DemoDwaWatki (wywołuje dwa wątki klasy ProstyWatek): public class ProstyWatek extends Thread { public ProstyWatek(String str) { // Konstruktor klasy super(str); // To nada nazwę wątkowi public void run() { // Metoda run() zawiera zadanie wątku for (int i = 0; i < 10; i++) { // Wykonuje pętlę 10 razy System.out.println(i + " " + getname()); // Wyprowadza indeks // iteracji i nazwę wątku W. Kasprzak: Programowanie zdarzeniowe 6-12

try { sleep((long)(math.random() * 1000)); // Uśpiony przez // pewien czas ale maksimum 1 sekundę. catch (InterruptedException e) { System.out.println("Wykonane! " + getname()); // Wyprowadza // komunikat, w tym nazwę wątku. // Klasa DemoDwaWatki : public class DemoDwaWatki { public static void main (String[] args) { // Utwórz i uruchom wątek new ProstyWatek ("Bahama").start(); // Utwórz i uruchom drugi wątek new ProstyWatek ("Bermudy").start(); Wynik - na przemian wyprowadzane są wyniki kolejnych wątków: W. Kasprzak: Programowanie zdarzeniowe 6-13 0 Bahama 0 Bermudy 1 Bermudy 1 Bahama 2 Bahama 2 Bermudy 3 Bermudy... Wykonane! Bermudy 9 Bahama Wykonane! Bahama W. Kasprzak: Programowanie zdarzeniowe 6-14

2) Implementacja interfejsu Runnable przez klasę programisty Przykład. Aplet Zegar wyświetlać będzie aktualny czas i odświeŝać obraz co sekundę - wykonując odpowiedni wątek. Klasa Zegar implementuje interfejs Runnable - w tym metodę run(). import java.awt.graphics; import java.util.*; import java.text.dateformat; import java.applet.applet; public class Zegar extends Applet implements Runnable { private Thread watekzegara = null; // Identyfikator dla obiektu wątku public void start() { // Metoda początkowa apletu if (watekzegara== null) { // Obiekt klasy Zegar przekaŝe siebie samego do konstruktora Thread // w ten sposób przekazana zostanie równieŝ implementacja metody // run() właściwa dla klasy Zegar do obiektu klasy Thread. watekzegara = new Thread(this, "Zegar"); //przekazanie do wątku watekzegara.start(); // Uruchom wątek. W. Kasprzak: Programowanie zdarzeniowe 6-15 // Zadanie wątku w metodzie run() public void run() { Thread mojwatek = Thread.currentThread(); while (watekzegara == mojwatek) { repaint(); // Metoda apletu wołająca metodę paint() try { Thread.sleep(1000); // Samo-zawieszenie wykonywania wątku catch (InterruptedException e){ // Gdy JVM przerwie "nasz sen" zakończymy wykonywanie pętli. // Nadpisanie metody paint() apletu public void paint(graphics g) { Calendar cal = Calendar.getInstance(); // Pobierz dzisiejszą datę Date date = cal.gettime(); // Pobierz czas, sformatuj go i wyświetl W. Kasprzak: Programowanie zdarzeniowe 6-16

DateFormat dateformatter = DateFormat.getTimeInstance(); g.drawstring(dateformatter.format(date), 5, 10); // Nadpisanie metody stop() klasy Applet, nie Thread public void stop() { watekzegara = null; //Zmienia warunek sprawdzany w metodzie run() Uwagi Dzięki mechanizmowi wątków aplet Zegar nie blokuje wykonywania się przeglądarki. Jeśli klasa juŝ dziedziczy po innej klasie niŝ Thread (jak np. Zegar po Applet) to stosujemy 2-gie rozwiązanie - implementację interfejsu Runnable. W przeciwnym razie - stosujemy rozwiązanie 1-sze dziedziczenie naszej klasy po Thread. W. Kasprzak: Programowanie zdarzeniowe 6-17 3) "Cykl Ŝycia" wątku yield start Nowo utworzony Wykonywany Zablokowany Zakończony W. Kasprzak: Programowanie zdarzeniowe 6-18 Zakończenie metody run() Utworzenie wątku Np. w metodzie start() apletu tworzony jest wątek o nazwie watekzegara: public void start() { if (watekzegara == null) { watekzegara = new Thread(this, "Zegar"); watekzegara.start();

Po utworzeniu wątek watekzegara jest w stanie nowo utworzony ( new Thread ) - jest pustym obiektem klasy Thread bez zasobów systemowych. MoŜna go jedynie uruchomić - metodą start() (inne odwołanie spowoduje powstanie wyjątku IllegalThreadStateException). Uruchomienie wątku public void start() { if (watekzegara == null) { watekzegara = new Thread(this, "Zegar"); watekzegara.start(); Powstają zasoby systemowe dla wątku, wybierany jest wątek i wołana jest dla niego metoda run(). Wątek będzie w stanie "wykonywania" ( running ). W. Kasprzak: Programowanie zdarzeniowe 6-19 Zablokowanie (zawieszenie) wątku Wykonywanie wątku zostaje zawieszone (stan zablokowany ), gdy: wywołana zostanie jego metoda sleep(); wątek woła metodę wait() dla oczekiwania na spełnienie warunku; wątek zablokuje się w oczekiwaniu na operację we/wy. Aby wątek powrócił do stanu wykonywania ze stanu zablokowania : musi upłynąć określony w wywołaniu sleep() czas podany liczbą milisekund; inny obiekt musi powiadomić nasz uśpiony wątek o zmianie warunku wywołując notify lub notifyall ; operacja we/wy, blokująca wątek, musi się zakończyć. Ustąpienie czasu procesora innym wątkom Wątek moŝe samoczynnie ustąpić czas procesora bez przechodzenia w stan zawieszenia wołając metodę yield() przejdzie on na koniec kolejki wątkom o jego priorytecie i da szansę na wykonanie się innym wątkom o tym samym priorytecie co ustępujący wątek. W. Kasprzak: Programowanie zdarzeniowe 6-20

Zakończenie wątku Wątek kończy się samodzielnie gdy zakończy się metoda run(). W przykładzie z apletem Zegar o zakończeniu pętli metody run() decyduje warunek: while (watekzegara == mojwatek) { Gdy przeglądarka opuszcza stronę, na której wykonuje się aplet wtedy woła ona metodę stop() dla apletu. W aplecie Zegar oznacza to, Ŝe: public void stop() { watekzegara = null; // Zmieniamy warunek wykonywania się run() Teraz metoda run() zakończy się -> wątek jest w stanie zakończony. Metoda klasy Thread: isalive() boolean isalive() Wynik zwracany przez isalive: true - gdy wątek jest w stanie wykonywania lub zablokowania ; false - gdy wątek jest w stanie nowo utworzony lub zakończony. W. Kasprzak: Programowanie zdarzeniowe 6-21 4) Priorytet wątku - szeregowanie Priorytet wątku decyduje o przydzieleniu czasu procesora jednemu z wątków będących w stanie wykonywania wybraniu go spośród konkurujących wątków. Java realizuje deterministyczny algorytm szeregowania ( scheduling ) w oparciu o priorytety: Wątek dziedziczy swój priorytet od wątku który go utworzył. Metoda setpriority umoŝliwia zmianę priorytetu - moŝliwe są wartości od MIN_PRIORITY do MAX_PRIORITY (stałe zdefiniowane w Thread). Wybierany jest wątek o najwyŝszym priorytecie - z dwóch równych następny z kolejki FIFO dla danego priorytetu. Wątek wykonuje się w procesorze dopóki nie zajdzie jeden z przypadków: Pojawi się wątek o wyŝszym priorytecie - w stanie wykonywania W. Kasprzak: Programowanie zdarzeniowe 6-22

Wątek ustępuje sam (metoda yield) lub kończy się jego metoda run. W systemach pracujących z podziałem czasu wątków gdy jego kwant czasu kończy się (zaleŝy to od implementacji klasy Thread). Wtedy kolejny wątek będzie wybrany do wykonania. Algorytm wyboru jest wywłaszczający - z chwilą pojawienia się wątku o wyŝszym priorytecie wykonywany wątek zostaje wywłaszczony. Java nie realizuje podziału czasu, wątek nie zostanie wywłaszczony przez inny wątek o tym samym priorytecie. Jednak implementacja klasy Thread w danym systemie moŝe realizować pracą z podziałem czasu CPU. W. Kasprzak: Programowanie zdarzeniowe 6-23 6.4 Synchronizacja pracy wątków Do tej pory rozpatrywaliśmy wątki, które mogą wykonywać się asynchronicznie względem siebie. Jednak wątki mogą wykorzystywać wyniki pracy innych wątków. W szczególności wątki mogą dzielić te same dane jednocześnie odwoływać się do nich. Wtedy ich praca musi być synchronizowana. Przykład. Producent generuje dane, zapisuje je do obiektu sklad klasy Skladzik a te są następnie odczytywane i "konsumowane" przez konsumenta. Niech producent generuje liczbę pomiędzy 0 a 9 (włącznie), zapamiętuje ją w obiekcie klasy Skladzik i wyświetla tę liczbę. Następnie "zasypia" na losowo dobierany czas (pomiędzy 0 a 100 ms) i znowu powtarza cykl generacji danych. public class Producent extends Thread { private Skladzik sklad; private int number; W. Kasprzak: Programowanie zdarzeniowe 6-24

public Producent (Skladzik c, int number) { sklad = c; this.number = number; public void run() { for (int i = 0; i < 10; i++) { skład.put(i); System.out.println("Producent #" + this.number + " połoŝył: " + i); try { sleep((int)(math.random() * 100)); catch (InterruptedException e) { Konsument pobiera wszystkie liczby jak szybko to jest moŝliwe. public class Konsument extends Thread { private Skladzik sklad; W. Kasprzak: Programowanie zdarzeniowe 6-25 private int number; public Konsument(Skladzik c, int number) { sklad = c; this.number = number; public void run() { int value = 0; for (int i = 0; i < 10; i++) { value = sklad.get(); System.out.println("Konsument #" + this.number+"pobrał: "+ value); // Klasa główna programu public class ProducentKonsumentTest { public static void main(string[] args) { Skladzik c = new Skladzik(); Producent p1 = new Producent(c, 1); // Utwórz producenta W. Kasprzak: Programowanie zdarzeniowe 6-26

Konsument c1 = new Konsument(c, 1); // Utwórz konsumenta p1.start(); // Uruchom wątek producenta c1.start(); // Uruchom wątek konsumenta Producent i konsument wymieniają dane poprzez wspólny obiekt Skladzik. Ale obie klasy "Konsument" i "Producent" nie synchronizują jawnie swoich działań, nie zapewniają tego, Ŝeby konsument otrzymywał kaŝdą daną tylko raz. Dlatego w tym przykładzie synchronizacja musi być zrealizowana na "niskim poziomie" przez metody "get" i "put" klasy Składzik. W innym przypadku łatwo moŝe powstać "hazard" w dostępie do obiektu przez oba wątki. W. Kasprzak: Programowanie zdarzeniowe 6-27 Sposoby synchronizacji: zablokowanie innemu wątkowi dostępu do obiektu (sekcja krytyczna) kwalifikator metody synchronized. powiadamianie się wątków - metody klasy Thread - wait, notify, notifyall. Sekcja krytyczna Przykład (c.d.) W podanym przykładzie metody put i get klasy Skladzik tworzą sekcje krytyczne. public class Skladzik { private int contents; private boolean available = false; public synchronized int get() {... public synchronized void put(int value) {... W. Kasprzak: Programowanie zdarzeniowe 6-28

Z kaŝdym obiektem klasy Skladzik związany będzie semafor. Jeśli wołana jest metoda synchronizowana to obiekt zostaje zablokowany. Inny wątek nie moŝe wykonać metody synchronizowanej na tym samym obiekcie do momentu odblokowania obiektu. UniemoŜliwia to powstanie hazardu w dostępie do obiektu. Metody notifyall i wait Wątki muszą się móc powiadamiać, Ŝe czekają na nie dane (wait) i Ŝe dane zostały dostarczone (notify, notifyall). Przykład (c.d.) Nowe definicje metod get i put klasy Skladzik public synchronized int get() { while (available == false) { try { wait(); // Oczekuj na połoŝenie danej przez producenta catch (InterruptedException e) { W. Kasprzak: Programowanie zdarzeniowe 6-29 available = false; notifyall(); // Powiadom producenta o pobraniu danej return contents; public synchronized void put(int value) { while (available == true) { try { wait(); // Oczekuj na pobranie danej przez konsumenta catch (InterruptedException e) { contents = value; available = true; notifyall(); // Powiadom konsumenta o połoŝeniu danej Metod wait zwalnia semafor "trzymany" przez "Konsumenta" na obiekcie "sklad" i oczekuje na powiadomienie od "Producenta". W. Kasprzak: Programowanie zdarzeniowe 6-30

Metoda notifyall budzi do Ŝycia wszystkie wątki, które oczekują na dany obiekt (w tym przypadku "sklad"). Konkurują one wtedy o dostęp do obiektu. Metoda notify w klasie Object: "budzi" dowolny wątek spośród oczekujących. W klasie Object zdefiniowano trzy wersje metody wait: wait() - oczekuje w nieskończoność na nadejście powiadomienia; wait (long timeout) - oczekuje najwyŝej liczbę timeout milisekund; wait (long timeout, int nanos) - oczekuje najwyŝej liczbę timeout milisekund plus nanos nanosekund. NaleŜy unikać "wygłodzenia i zakleszczeń wątków. "Wygłodzenie" wątku wystąpi gdy jeden lub więcej wątków nie otrzymuje dostępu do zasobów. Zakleszczenie to końcowe stadium wygłodzenia - wątki czekają na spełnienie niemoŝliwego warunku. W. Kasprzak: Programowanie zdarzeniowe 6-31 6.5 Grupowanie wątków Klasa java.lang.threadgroup - umoŝliwia zebranie wątków w jeden obiekt i jednoczesną manipulację nimi wszystkimi. Podczas tworzenia wątku zostaje on przydzielony do jakieś grupy i musi juŝ tam pozostać. Domyślna grupa wątków dla aplikacji to jest main. W. Kasprzak: Programowanie zdarzeniowe 6-32

Utworzenie nowej grupy wątków o nazwie name: ThreadGroup(String name) ThreadGroup(ThreadGroup parent, String name) Np. utworzenie grupy jako elementu domyślnej grupy wątków main: ThreadGroup mythreadgroup = new ThreadGroup( Moja grupa"); Jeśli podczas tworzenia nowego wątku nie specyfikujemy jego grupy to zostanie on zaliczony do grupy tego wątku, który go utworzył. Trzy konstruktory klasy Thread umoŝliwiają utworzenie i dodanie wątku do jawnie podanej grupy: public Thread(ThreadGroup group, Runnable runnable) public Thread(ThreadGroup group, String name) public Thread(ThreadGroup group, Runnable runnable, String name) Np. Utworzenie wątku w nowej grupie: Thread mythread = new Thread(myThreadGroup, "watek w grupie"); Określenie grupy dla wątku - metoda getthreadgroup, np.: thegroup = mythread.getthreadgroup(); W. Kasprzak: Programowanie zdarzeniowe 6-33 Metody klasy ThreadGroup Zarządzanie kolekcją activecount() - podaje liczbę aktywnych wątków w grupie; activegroupcount() podaje liczbę aktywnych grup wątków w grupie. Klasa implementuje interfejs Enumerate, co pozwala m.in. na pobranie listy aktywnych wątków tej grupy. Np. public class EnumerateTest { public void listcurrentthreads() { ThreadGroup currentgroup = Thread.currentThread().getThreadGroup(); int numthreads = currentgroup.activecount(); Thread[] listofthreads = new Thread[numThreads]; currentgroup.enumerate(listofthreads); for (int i = 0; i < numthreads; i++) System.out.println("Wątek #" + i + " = " + listofthreads[i].getname()); W. Kasprzak: Programowanie zdarzeniowe 6-34

Przetwarzanie grupy wątków getmaxpriority, setmaxpriority // Ustawianie priorytetu getdaemon, setdaemon getname getparent, parentof tostring Np. public class MaxPriorityTest { public static void main(string[] args) { ThreadGroup groupnorm = new ThreadGroup( // Utworzenie grupy "Normalny priorytet grupy"); Thread prioritymax = new Thread(groupNORM, // Dodanie wątku "Wątek o maksymalnym priorytecie"); // Ustaw priorytet wątku na maksymalnie moŝliwy (10) prioritymax.setpriority(thread.max_priority); // Ustaw maksymalny priorytet grupy na normalny (5) groupnorm.setmaxpriority(thread.norm_priority); System.out.println("Maksymalny priorytet grupy = " + W. Kasprzak: Programowanie zdarzeniowe 6-35 groupnorm.getmaxpriority()); System.out.println("Priorytet wątku = " + prioritymax.getpriority()); Wynik wykonania: Maksymalny priorytet grupy = 5 Priorytet wątku = 10 Metody operujące na stanie wszystkich wątkach grupy jednocześnie resume() - wznów stop() - zatrzymaj suspend() - zawieś Metody te zmieniają stan wszystkich wątków grupy jednocześnie. Uwaga: poniewaŝ wykorzystują one metody resume, stop i suspend klasy Thread nie są one zabezpieczone przed wątkami (tzn. jednoczesnym uŝyciem przez więcej niŝ jeden wątek). W. Kasprzak: Programowanie zdarzeniowe 6-36

Metody kontroli dostępu Obie klasy współpracują z klasą SecurityManager. Klasy Thread i ThreadGroup posiadają metodę checkaccess, która wywołuje metodę checkaccess aktualnego security managera, sprawdzającą prawo dostępu dla grupy - zgłasza wyjątek SecurityException jeśli nie jest to moŝliwe. PoniŜsze metody klasy ThreadGroup wywołują metodę checkaccess zanim wykonają swoją akcję (regulowany dostęp): ThreadGroup(ThreadGroup parent, String name) setdaemon(boolean isdaemon) setmaxpriority(int maxpriority) stop suspend resume destroy W. Kasprzak: Programowanie zdarzeniowe 6-37 Lista metod klasy Thread, które wywołują checkaccess zanim wykonają swoją akcję: konstruktory specyfikujące grupę wątków; stop suspend resume setpriority(int priority) setname(string name) setdaemon(boolean isdaemon) W. Kasprzak: Programowanie zdarzeniowe 6-38

Podsumowanie Pakiety wspomagające programowanie wielowątkowe java.lang.thread - Bazowa klasa dla wątków w Javie. java.lang.runnable - Interfejs Runnable zawiera metodę run, wymaganą dla kaŝdego wątku. java.lang.object - Klasa główna Object zawiera definicje 3 metod przeznaczonych do synchronizacji wątków: wait, notify, notifyall. java.lang.threadgroup - KaŜdy wątek naleŝy do jakieś grupy, zwykle skupiającej powiązane ze sobą wątki. java.lang.threaddeath - Wymuszenie zakończenia pracy wątku jest moŝliwe dzięki przekazaniu mu obiektu klasy ThreadDeath. Elementy języka wspomagające wątki Słowo kluczowe w Javie przeznaczone do synchronizacji wątków: synchronized. Elementy środowiska wykonania wspomagające wątki W środowisku wykonania Javy występuje szeregowanie wątków. W. Kasprzak: Programowanie zdarzeniowe 6-39