Programowanie wielowątkowe. Tomasz Borzyszkowski



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

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

Wątki w Javie. Piotr Tokarski

Kurs programowania. Wykład 8. Wojciech Macyna

Język Java wątki (streszczenie)

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

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

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

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

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

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

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

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

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

Programowanie komputerów

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

Współbieżność w Javie

Język Java wątki (streszczenie)

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

Współbieżność w Javie

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

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

Programowanie współbieżne i rozproszone

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

Dziedziczenie. Tomasz Borzyszkowski

Podstawy współbieżności

Monitory. Jarosław Kuchta

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

Multimedia JAVA. Historia

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

Aplikacje w środowisku Java

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

Dariusz Brzeziński. Politechnika Poznańska, Instytut Informatyki

Język Java część 2 (przykładowa aplikacja)

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

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

dr Krzysztof Podlaski

Programowanie obiektowe

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

Wstęp do Java. Operacje Wejścia-Wyjścia Programowanie Wielowątkowe. dr Krzysztof Podlaski. Wydział Fizyki i Informatyki Stosowanej

Pakiety i interfejsy. Tomasz Borzyszkowski

Przetwarzanie wielowątkowe przetwarzanie współbieżne. Krzysztof Banaś Obliczenia równoległe 1

Java - wprowadzenie. Programowanie Obiektowe Mateusz Cicheński

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

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

Systemy operacyjne. Zajęcia 11. Monitory

Marcin Luckner Politechnika Warszawska Wydział Matematyki i Nauk Informacyjnych

Język Java część 2 (przykładowa aplikacja)

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

Języki i techniki programowania Ćwiczenia 2

Programowanie współbieżne Wykład 8 Podstawy programowania obiektowego. Iwona Kochaoska

Programowanie obiektowe

Zaawansowane programowanie w C++ (PCP)

Interfejsy i klasy wewnętrzne

Model pamięci. Rafał Skinderowicz

using System;... using System.Threading;

Dziedziczenie. dr Jarosław Skaruz

Klasy abstrakcyjne i interfejsy

Programowanie współbieżne Zadanie 5 - Podstawowe problemy programowania współbieżnego

4. Procesy pojęcia podstawowe

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

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

Wprowadzenie do programowania współbieżnego

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

Diagram klas UML jest statycznym diagramem, przedstawiającym strukturę aplikacji bądź systemu w paradygmacie programowania obiektowego.

Programowanie obiektowe - 1.

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

Programowanie obiektowe

Technologie obiektowe

Java. Programowanie Obiektowe Mateusz Cicheński

Kurs programowania. Wstęp - wykład 0. Wojciech Macyna. 22 lutego 2016

JAVA W SUPER EXPRESOWEJ PIGUŁCE

1. Które składowe klasa posiada zawsze, niezależnie od tego czy je zdefiniujemy, czy nie?

Informatyka I. Klasy i obiekty. Podstawy programowania obiektowego. dr inż. Andrzej Czerepicki. Politechnika Warszawska Wydział Transportu 2018

Projektowanie oprogramowania systemów PROCESY I ZARZĄDZANIE PROCESAMI

Wzorce Strukturalne. Adapter: opis. Tomasz Borzyszkowski

WSNHiD, Programowanie 2 Lab. 2 Język Java struktura programu, dziedziczenie, abstrakcja, polimorfizm, interfejsy

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

Dokumentacja do API Javy.

TEMAT : KLASY DZIEDZICZENIE

Java - tablice, konstruktory, dziedziczenie i hermetyzacja

Obiekt klasy jest definiowany poprzez jej składniki. Składnikami są różne zmienne oraz funkcje. Składniki opisują rzeczywisty stan obiektu.

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

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

Mechanizmy pracy równoległej. Jarosław Kuchta

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

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

Podstawy Programowania Obiektowego

Java Język programowania

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

Programowanie współbieżne Wykład 7. Iwona Kochaoska

Programowanie obiektowe

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

Technologie i usługi internetowe cz. 2

Wykład Ćwiczenia Laboratorium Projekt Seminarium

KLASA UCZEN Uczen imię, nazwisko, średnia konstruktor konstruktor Ustaw Wyswietl Lepszy Promowany

Kurs WWW. Paweł Rajba.

PHP 5 język obiektowy

Programowanie współbieżne Laboratorium nr 12

Transkrypt:

Programowanie wielowątkowe Tomasz Borzyszkowski

Wątki a procesy Jako jeden z niewielu języków programowania Java udostępnia użytkownikowi mechanizmy wspierające programowanie wielowątkowe. Program wielowątkowy zawiera kilka równoległych ścieżek wykonania. Każda tak ścieżka nazywa się wątkiem. Wielowątkowość jest specyficzną formą wielozadaniowości. Istnieją dwa typy wielozadaniowości: Bazujący na procesach: pozwala na równoległe wykonanie kilku programów Bazujący na wątkach: pojedynczy program może wykonywać kilka zadań równolegle Typ procesowy występuje we większości systemów operacyjnych. Proces posiada bogate środowisko wykonania, swoją przestrzeń adresową itp. Komunikacja i przełączanie między procesami są kosztowne. Wątki są tańsze, ponieważ bazują na jednym procesie i współdzielą jego zasoby. Pozwalają maksymalnie wykorzystać procesor. 2

Cykl życia wątku Wątek działa sleep wait new Thread działa czeka start wyłączony Koniec metody run Powyższy diagram przedstawia cykl życia wątku. Kodowanie poszczególnych etapów życia wątku przedstawimy w dalszej części wykładu. 3

Wątki priorytety Java z każdym wątkiem programu kojarzy priorytet, informujący o tym jak należy traktować wątek w stosunku do innych wątków programu. Priorytet jest liczbą całkowitą określającą relatywną ważność wątku w stosunku do innych wątków. Priorytet wątku nie ma wpływu na szybkość wykonywania wątku, a jedynie na pierwszeństwo w wyborze do wykonania (zmiany kontekstu wykoniania). Reguły rządzące tym kiedy zmieniać kontekst wykoniania są następujące: Wątek może dobrowolnie odstąpić prawo do wykonania innym wątkom. Sytuacja taka ma miejsce, gdy wątek musi czekać na zwolnienie zasobu lub, gdy wykonał metodę sleep. Wybierany jest wówczas wątek z oczekujących o najwyższym priorytecie. Wątek może zostać wyparty przez wątek o wyższym priorytecie. Tj., gdy tylko wątek o wyższym priorytecie potrzebuje procesor, to go bierze. 4

Wątek główny Wraz z uruchomieniem programu napisanego w Java jeden wątek, zwany wątkiem głównym, startuje natychmiast. Wątek główny jest ważny, ponieważ: Jest wątkiem mogącym zapoczątkowywać inne wątki, zwane wątkami potomnymi Często musi być ostatnim wątkiem kończącym wykonanie programu Wątek główny niczym nie różni się od innych wątków programu. By uzyskać nad nim kontrolę musimy utworzyć do niego referencję, korzystając z publicznej statycznej metody currentthread() klasy Thread. Metoda ta oddaje referencję do wątku, w którym została wywołana. Zobacz: CurrentThreadDemo.java 5

Tworzenie własnego wątku By utworzyć nowy wątek trzeba utworzyć obiekt typu Thread. Można to zrobić na dwa sposoby: Zaimplementować interfejs Runnable Rozszerzyć klasę Thread Implementacja Runnable Zobacz: NewThreadDemo.java Interfejs Runnable jest abstrakcją wykonywalnego kodu. Można utworzyć wątek bazując na dowolnym obiekcie implementującym ten interfejs. By implementować ten interfejs, klasa musi jedynie implementować pojedynczą metodę: public void run() Ciało tej metody stanowi kod wątku. Wątek taki kończy się wraz z zakończeniem działania metody run(). Wywołanie konstruktora: Thread(Runnable obwątku, String nazwa); Tworzy nowy wątek bazując na obiekcie obwątku z nazwą nazwa. Metoda start() uruchamia metodę run() obiektu wątku. 6

Rozszerzanie klasy Thread Kolejnym sposobem tworzenia własnych wątków jest definiowanie nowych klas dziedziczących po klasie Thread, następnie tworzenie ich instancji. Klasa rozszerzająca musi nadpisać metodę run() klasy Thread. Podobnie jak w poprzednim przykładzie musimy wykonać metodę start() by rozpocząć wykonanie nowego wątku. Zobacz: ExtendThreadDemo.java Co lepsze? Przedstawiliśmy dwa sposoby tworzenia nowych wątków. Który z nich jest lepszy? Zgodnie z metodologią obiektową dziedziczenie klas ma sens, gdy klasa pochodna zmienia coś istotnego w klasie dziedziczonej. W naszym przypadku była to tylko metoda run(). Wydaje się, że w takim przypadku bardziej odpowiednia jest implementacja interfejsu Runnable. Powyższe rozważania traktują raczej o dobrym stylu, niż o poprawności kodowania. Zobacz: MultiThreadDemo.java 7

Metody isalive() i join() W poprzednich programach staraliśmy się nie doprowadzać do sytuacji, w której wątek główny kończył by się zanim zakończą się wątki potomne. Efekt ten osiągaliśmy przez odpowiednio długie usypianie wątku głównego. Takie rozwiązanie jest rzadko satysfakcjonujące w realnych programach. Skąd więc wątek może wiedzieć, że inny wątek się zakończył? Odpowiedzi na to pytanie mogą udzielić dwie metody klasy Thread: final boolean isalive() oddająca true, gdy wątek, dla którego ją wywołujemy działa, false w przeciwnym przypadku final void join() throws InterruptedException metoda czeka, aż wątek, dla którego wywołujemy zakończy się; dodatkowe wersje join pozwalają podać maksymalny czas oczekiwania na zakończenie wątku Zobacz: JoinThreadDemo.java 8

Priorytety wątków Zobacz: PriorityDemo.java W praktyce wątki o wyższym priorytecie powinny mieć łatwiejszy dostęp do procesora niż wątki i niższym priorytecie. W rzeczywistości dostęp do procesora zależy od wielu czynników. Najważniejszym z nich jest implementacja w danym systemie wielozadaniowości. Aby zapewnić wszystkim wątkom dostęp do procesora, także w środowiskach bez wywałaszczania, wątki powinny oddawać sterowanie co jakiś czas. Do ustawiania priorytetu wątku służy metoda: final void setpriority(int poziom) Parametr poziom, to nowy priorytet wątku. Jego wartości powinny być z zakresu od MIN_PRIORITY (1) do MAX_PRIORITY (10). Domyślnym priorytetem jest NORM_PRIORITY (5). Kompilator optymalizując kod zakłada, że wykonanie bieżącego kodu zależy jedynie od niego samego. W przypadku wielu wątków często wątki mogą wpływać na siebie. Słowo volatile wstrzymuje optymalizację wybranego kodu. 9

Synchronizacja koncepcje Gdy dwa lub więcej wątków chce korzystać ze wspólnych zasobów, potrzebują pewnego sposobu upewnienia się, że z zasobu będzie korzystać tylko jeden wątek w jednym czasie. W informatyce taki sposób upewniania się nazywa się synchronizacją. Zwykle synchronizacja wymaga wykonania pewnego protokołu przez wątki. Java dostarcza własny sposób synchronizacji na poziomie języka. Synchronizacja jest zapewniana w Java przez tzw. monitory. Monitor jest obiektem zapewniającym wzajemne wykluczanie wątków. Tylko jeden wątek może być w posiadaniu jednego monitora w jednym czasie. Wątek wchodzący do tzw. sekcji krytycznej otwiera monitor. Wszystkie inne wątki próbujące otworzyć ten sam monitor są wstrzymane do czasu aż pierwszy wątek opuści monitor. Wątki takie nazywamy oczekującymi na dostęp. Większość języków programowania nie implementuje mechanizmów wzajemnego wykluczania (patrz C, C++, Pascal,...). 10

Synchronizacja przykład Synchronizacja w Java nie jest zbyt skomplikowana. Każdy obiekt w Java posiada związany z nim niejawny obiekt monitora. Aby otworzyć monitor obiektu trzeba wywołać jego metodę zdefiniowaną z modyfikatorem synchronized. Dopóki wątek znajduje się wewnątrz metody synchronizowanej każdy inny wątek chcący wywołać tę lub inną metodę synchronizowaną obiektu, musi czekać aż pierwszy wątek opuści metodę synchronizowaną. Aby lepiej zrozumieć działanie monitorów w Java, prześledźmy przykład programu, w którym wątki mogą dostać się do sekcji krytycznej bez synchronizacji. Zobacz: NoSynch.java Poprawka w poprzednim programie polega na synchronizowaniu metody call() klasy CallMe. Po poprawce tylko jeden wątek będzie mógł korzystać z metody call() w jednym czasie. Zobacz: Synch.java 11

Komenda synchronized Zobacz: Synchronized.java Użycie metod synchronizowanych jest prostym sposobem uzyskania wzajemnego wykluczania wątków. Niestety nie zawsze może być stosowany. Wyobraźmy sobie, że chcemy synchronizować dostęp wątków do obiektu, który nie był zaprojektowany do używania przez wiele wątków. Tj. klasa ta nie używa metod synchronizowanych. Co więcej klasa ta nie była projektowana przez nas i nie mamy dostępu do kodu źródłowego. W jaki sposób możemy synchronizować dostęp do tego obiektu? Odpowiedź: Wywołania metod, które powinny być synchronizowane wstawiamy do bloku synchronized: synchronized (obiekt) { // synchronizowane komendy } Powyżej obiekt jest synchronizowanym obiektem. Wywołania metod synchronizowanego obiektu będą możliwe tylko wtedy, gdy obiekt zdoła otworzyć monitor obiektu. 12

13 Wątki komunikacja Dotychczas wątki jedynie blokowały dostęp do zasobów krytycznych. Po zwolnieniu zasobu wątki konkurują o zwoniony zasób. Polegając na tym mechaniźmie nie możemy wyrazić bardziej subtelnych związków między wątkami, takich jak: uczciwość, żywotność,.... Java prócz mechanizmów zapewniających wzajemne wykluczanie oferuje mechanizm wymiany sygnałów między współbieżnymi wątkami. Służą do tego metody finalne klasy Object: wait(), notify() i notifyall(). Metody te mogą być wywołane tylko z metody synchronizowanej. Ich znaczenie: wait() informuje wątek wywołujący by opuścił monitor i zasnął do czasu aż inny wątek otworzy ten sam monitor i wywoła metodę notify() lub notifyall() notify() budzi wątek, który jako pierwszy wywołał wait() na tym samym obiekcie notifyall() budzi wszystkie wątki, które wywołały wait() na tym samym obiekcie; wątek o najwyższym priorytecie działa, reszta śpi

Wątki producent konsument Produkcja Bufor Konsumpcja Producent Konsument Implementacja powyższego modelu producenta i konsumenta z buforem jednoelementowym wymaga użycia mechanizmu sygnałów. Niepoprawny sposób implementacji zapewniający wyłącznie wzajemne wykluczanie w dostępie do bufora można znaleźć w pliku: ProdKonsErr.java Poprawną implementację można znaleźć w pliku: ProdKons.java Zadanie: zaimplementować model producenta i konsumenta z buforem wieloelementowym. 14

Wątki zakleszczenie Istnieje specjalny typ błędu związanego z wielozadaniowością i wielowątkowością w szególności. Jest nim zakleszczenie. Z zakleszczeniem mamy do czynienia np. wtedy, gdy jeden wątek otwiera monitor obiektu X, drugi otwiera monitor obiektu Y, i pierwszy próbuje wywołać synchronizowaną metodę obiektu Y, natomiast drugi próbuje wywołać synchronizowaną metodę obiektu X. Oba wątki będą czekały na zwonienie zasobów blokując je sobie wzajemnie. Taką sytuację nazywamy zakleszczeniem. Zakleszczenie jest trudne do wykrycia ponieważ: W programie, w którym zakleszczenie jest możliwe zwykle rzadko do niego dochodzi; oba wątki muszą w tym samym czasie być w odpowiednim miejscu kodu W wielu programach występuje więcej niż dwa wątki i dwie synchronizowane metody; może dojść do zakleszczeń zespołowych Zobacz: Zakleszczenie.java 15

Wstrzymaj, wznów, stop W Java 1.1 wstrzymanie, wznowienie i zatrzymanie wątku odbywało się przez wywołanie metod suspend(), resume() i stop() klasy Thread. Metody te nie są stosowane w Java 2. Zobacz: Suspend1_1.java W Java 2 zrezygnowano z powyższych metod, ponieważ mogły doprowadzić do poważnych błędów programu, np.: wstrzymanie wątku, gdy ten blokuje zasób krytyczny spowoduje zablokowanie tego zasobu na zawsze, zatrzymanie wątku w trakcie zapisu danych może spowodować niekompletność zapisywanych danych. W Java 2 należy tak zaprojektować metodę run() by wątek sam, raz na jakiś czas, sprawdzał czy powinien wstrzymać, wznowić czy zatrzymać wykonanie. Zwykle osiąga się to za pomocą flag i metod wait() i notify(). Zobacz: Suspend2.java 16

Pięciu filozofów F5 F1 Stół F2 Filozof myśli. Gdy zgłodnieje podnosi prawy widelec, następnie lewy i je. Po zakończonym posiłku odkłada najpierw prawy a potem lewy widelec i zaczyna myśleć, aż zgłodnieje, itd... F4 F3 Zadanie: 1. Zaimplementować w Java problem pięciu filozofów za pomocą wątków. 2. Rozwiązać zadanie tak by nie dochodziło do zagłodzenia żadnego filozofa. 17