Wątki
Wątek - definicja Ciąg instrukcji (podprogram) który może być wykonywane współbieżnie (równolegle) z innymi programami, Wątki działają w ramach tego samego procesu Współdzielą dane (mogą operować na tych samych danych) -> programowanie rozproszone ze współdzieleniem pamięci Obsługą wątków zajmuje się dany proces a nie system (obsługą procesów zajmuje się system) Przykład Wykorzystanie kilku rdzeni procesora jednocześnie Zrównoleglenie obliczeń Jednoczesna obsługa ekranu i procesu obliczeniowego
Implementacja wątków w Javie Wątki wymagają menadżera wątków procedury przydzielającej i dbającej o kolejność wykonywania wątków. W Javie jest to zaimplementowane wewnątrz JVM Możliwe są dwa sposoby tworzenia programów wielowątkowych Poprzez dziedziczenie po klasie Thread Poprzez implementację interfejsu Runnable
Dziedziczenie po klasie Thread Musimy wówczas przeciążyć metodę run: Uruchomienie osobnego wątku:
Implementacja Runnable Musimy wówczas zdefiniować metodę run: Uruchomienie osobnego wątku:
Metody klasy Thread Uruchamianie / Zatrzymywanie Start uruchomienie wątku Stop zatrzymanie wątku Run program wykonywany w osobnym wątku
Metody klasy Thread Uruchamianie / Zatrzymywanie Start uruchomienie wątku Stop zatrzymanie wątku Run program wykonywany w osobnym wątku Teoretycznie też działa ale tak nie wolno bo nie mamy współbieżności. Całość wykonywana jest sekwencyjnie
Ważne metody związane ze współbieżnością sleep(long ms) uśpienie wątku na określony czas wait() wprowadzenie wątku w stan oczekiwania notify()/notifyall() wzbudzenie wątku/wątków ze stanu oczekiwania Metody wait() i notify() (notifyall()) muszą być wywoływane w bloku/metodzie synchronized na tym samym obiekcie. void join([long milsec [, int nanosec]]) oczekiwanie na zakończenie wątku void setdaemon(boolean on) ustawienie wątku jako demona boolean isdaemon() czy wątek jest demonem boolean isalive() sprawdzenie czy wątek działa void interrupt(); - przerwanie działania wątku
Priorytety wątków Wątki mogą posiadać różne priorytety (ważności wykonywania) Zasada działania priorytetów: dopiero jak obsłużono wątki ważne obsługujemy wątki mniej ważne void setpriority(int priority) ustawianie priorytetu wątku, int getpriority() odczytanie priorytetu wątku. yield() oddanie czasu innym wątkom o tym samym priorytecie Stałe zdefiniowane w klasie w klasie Thread (typu final): Thread.MIN_PIORITY najniższy priorytet Thread.MAX_PIORITY maksymalny priorytet Thread.NORM_PIORITY normalny priorytet
Identyfikacja wątków String getname() pobranie nazwy wątku void setname(string name) ustawienie nazwy wątku long getid() zwrócenie identyfikatora wątku (unikatowa wartość)
Jeszcze kilka metod związanych z wątkami isalive() sprawdzenie czy wątek żyje setname(string name) nadanie wątkowi nazwy (pozwala na jego identyfikację) String getname() zwraca nazwę wątku
Wątki - problemy Często wątki korzystają ze wspólnych danych problem bezpieczeństwa danych Jednorodność danych (podczas odczytu dane nie mogą ulegać zmianie) Przykład: podczas odczytu danych przez jeden wątek drugi w międzyczasie dokonał ich modyfikacji. Współdzielone dane należy chronić przez tzw zakładanie zamka (blokowanie dojścia do danego obiektu/bloku instrukcji)
Sekcja krytyczne Sekcja krytyczna - w programowaniu współbieżnym fragment kodu programu, w którym korzysta się z zasobu dzielonego, a co za tym idzie w danej chwili może być wykorzystywany przez co najwyżej jeden wątek. i = 0 Współdzielony obszar pamięci Wątek A Operacja na i Wątek B Wątek B Operacja na i Wątek B czas
Wątki problemy Co jeśli sekcja krytyczna jest niepoprawnie zaimplementowana Sekcja krytyczna
Przykład Zmienna statyczna np. licznik Inkrementujemy licznik Czekamy chwilę Tworzymy obiekt wątku 1 Tworzymy obiekt wątku 2 Czekamy aż skończy wątek 1 Uruchamiamy wątki Czekamy aż skończy wątek 2 Jaki wynik?
Przykład Zmienna statyczna np. licznik Inkrementujemy licznik Czekamy chwilę Tworzymy obiekt wątku 1 Tworzymy obiekt wątku 2 Czekamy aż skończy wątek 1 Uruchamiamy wątki Czekamy aż skończy wątek 2 Jaki wynik?
Dlaczego to nie działa Każdy wątek ma swój własny lokalny obszar pamięci, zmienne współdzielone domyślnie przechowywane są w postaci lokalnej kopi osobno dla każdego wątku Zmienna static liczbik Współdzielona między wątkami Lokalna kopia licznik Lokalna kopia licznik Wątek 1 Wątek 2
Volatile Volatile oznacza zmienną we wspólnym współdzielonym obszarze pamięci Zmienna static volatile liczbik Współdzielona między wątkami Wspólna kopia licznik Wspólna kopia licznik Wątek 1 Wątek 2
Volatile Volatile oznacza zmienną we wspólnym współdzielonym obszarze pamięci Czy teraz działa? Zmienna static volatile liczbik Współdzielona między wątkami Wspólna kopia licznik Wspólna kopia licznik Wątek 1 Wątek 2
Volatile Volatile oznacza zmienną we wspólnym współdzielonym obszarze pamięci Czy teraz działa? Zmienna static volatile liczbik Współdzielona między wątkami Wspólna kopia licznik Wspólna kopia licznik Wątek 1 Wątek 2
Problem!!! W1 odczytuje 0 W2 odczytuje 0 Wątek 1 Wątek 2 For ( ) End Pobierz licznik For ( ) Pobierz licznik Dodaj licznik + 1 Dodaj licznik + 1 Zapisz licznik Tak być powinno End Zapisz licznik licznik = 0 For ( ) Wątek 1 Wątek 2 End Pobierz licznik Dodaj licznik + 1 Tak może być For ( ) Pobierz licznik Zapisz licznik Dodaj licznik + 1 End W1 i 0+1 = 1 W2 i 0+1 = 1 Zapisz licznik W1 zapisuje 1 W2 zapisuje 1 Powinno być 2
Zmienne Atomic Zmienne typu ATOMIC to proste zmienne gwarantujące poprawną współbieżność Klasa AtomicBoolean AtomicInteger AtomicLong AtomicReference ( )
Bezpieczeństwo wątków - zamki Zakładanie zamków na obiekcie: Wykorzystanie metody typu synchronized Wykorzystanie bloku typu sychronized np.: private double stankonta; public synchronized wplata(double ile){ stankonta += ile; } public synchronized wyplata(double ile){ stankonta -= ile; } Zasada działania podczas uruchomienia metody synchronized następuje zatrzaśnięcie blokady (na czas realizacji tej metody) Zakończenie wykonywania metody zwalnia blokadę inne wątki też mogą korzystać z danego obiektu.
Bezpieczeństwo wątków - zamki Sekcja krytyczna
Bezpieczeństwo wątków - zamki Sekcja krytyczna Każdy obiekt ma wewnętrzną zmienną typu boolean określającą zamek. Wywołanie synchronized zatrzaskuje zamek Gdy zamek jest zatrzaśnięty inne wątki nie mają dostępu do zmiennej przechodzą w stan wait Wyjście z metody synchronized zwalnia zamek Inni mogą wejść
Opis problemu: Wątki przykład Producent - Konsument Typowy przykład programowania współbieżnego Producent produkuje towar, po jego wyprodukowaniu umieszcza go w magazynie Jeśli produkt jest w magazynie, producent nie może do niego włożyć nowego towaru. Może włożyć dopiero jak konsument opróżni magazyn Konsument czeka, aż pojawi się towar w magazynie Gdy jest towar w magazynie konsument pobiera go i czeka na nowy towar Interpretacja przesyłanie komunikatów między dwoma wątkami
Wątki przykład Producent - Konsument Wait zwalnia zatrzask związany z synchronized Wait zwalnia zatrzask związany z synchronized
Programowanie rozproszone
RMI remote method invocation RMI - Zdalne wywoływanie metod Pozwala na wywoływanie metod obiektu znajdującego się na zdalnym komputerze- > architektura klient-serwer. Rejestracja usług w rejestrze. Rejestr mapowanie: nazwa -> host + port
RMI
RMI tworzenie zdalnego obiektu 1) Stworzenie interfejsu, obsługiwanego przez zdalny obiekt Metoda obsługiwana przez zdalny obiekt 2) Implementacja interfejsu -> stworzenie klasy
RMI implementacja serwera Tworzenie menadżera bezpieczeństwa Tworzenie instancji zdalnego obiektu (będzie ona odpowiadała za realizację zadań) Przygotowanie obiektu do zdalnego wywoływania metod Skojarzenie rejestratora nazw z określoną przez nas nazwą Pobranie lub stworzenie rejestratora nazw
RMI implementacja klienta Tworzenie menadżera bezpieczeństwa Pobranie rejestratora nazw zdalnych obiektów. Jeśli rejestr na innym hoście to podać adres do hosta Pobranie rejestratora nazw zdalnych obiektów. Jeśli rejestr na innym hoście to podać adres do hosta Wywołanie zdalnej metody
RMI - Uwagi Uwaga konieczne jest załadowanie plików polis bezpieczeństwa zarówno dla serwera jak i dla klienta Plik polis określa uprawnienia wywołania kodu zarówno na kliencie jak i na serwerze. Przykładowy plik polisy: Pełne uprawnienia na wszystko grant { permission java.security.allpermission; }; java -Djava.security.policy=server.policy Serwer java -Djava.security.policy=client.policy Klient