Java – wątki

Wątki w Javie można wykorzystać na kilka sposobów:
dziedziczenie kompletu cech klasy Thread (java.lang)
implementacja interfejsu Runnable (java.lang)
implementacja interfejsu Callable (java.lang)

W języku Java nie ma wielodziedziczenia, w związku z tym dziedziczenie cech klasy Thread blokuje wykorzystanie cech innych klas. Zaleca się stosowanie implementacji interfejsu Runnable.

W przypadku Runnable run() jest typu void. Brak jest również klauzuli throws. Metoda run() w swoim ciele zawiera instrukcje, które ma wykonać wątek.

Callable posiada metodę call(), która posiada typ generyczny. call() również posiada klauzulę throws. Metoda call() w swoim ciele zawiera instrukcje, które ma wykonać wątek.

Aby uruchomić wątek nalezy utworzyć instancję klasy Thread wprowadzając w konstruktorze referencje obiektu klasy implementującej Runnable i wywołać na niej (instancja Thread) metodę start().

Główne metody klasy Thread:
start() – uruchomienie wątku,
stop() – zakończenie wątku (metoda niezalecana),
run() – kod wykonywany w ramach wątku.
sleep() – zawieszenie wykonania wątku na dany okres czasu,
join() – oczekiwanie na zakończenie innego wątku,
wait() – oczekiwanie w monitorze,
notify() – odblokowanie wątku zablokowanego na monitorze,
notifyAll() – odblokowanie wszystkich wątków zablokowanych na
monitorze,
interrupt() – odblokowanie zawieszonego wątku

Przykład utworzenia i wykorzystania wątku w oparciu o implementację Runnable:

Przykład klasy implementującej Runnable
Tworzenie wątków
Działanie programu

Wątki w Java mogą znaleźć się w jednym z czterech stanów:
utworzony (ang. new thread) – obiekt utworzony ale jeszcze przed wykonaniem metody start()
wykonywalny (ang. runnable) – wątek z przydzielonymi zasobami lecz jeszcze bez przydziału procesora
zablokowany (ang. blocked) – wątek nie może być wykonywany z powodu braku zasobów
zakończony (ang. dead) – po wykonaniu metody stop(). Zalecanym sposobem zakończenia wątku jest zakończenie metody run()

Przejście od stanu wykonywalny do zablokowany następuje gdy wątek chce wejść do zablokowanego monitora lub wykonana została metoda wait(), join(), sleep() lub wątek wykonał operację wejścia / wyjścia.

Powrót od stanu zablokowany do wykonywany następuje gdy monitor został odblokowany lub inny wątek odblokował zablokowany wątek za pomocą stosownych metod lub upłynął interwał sleep tudzież operacja wejścia/wyjścia się zakończyła.

Wątki operują we wspólnym obszarze pamięci stąd aby program generował deterministyczne wyniki nalezy użyć mechanizmów synchornizacji. Sekcje krytyczne w języku Java to metody albo bloki synchronizowane. Każda instancja klasy Object posiada Monitor, ograniczający dostęp do obiektu. Blokada ta jest sterowana słowem kluczowym synchronized. Słowo to znajduje się w definicji metody lub bloku instrukcji. Wywołanie metody synchronizowanej blokuje monitor do czasu zakończenia jej działania.

Zadanie: Na podstawie przedłożonej paczki z kodem źródłowym zaimplementować wielowątkowe mnożenie macierzy. Zabezpieczyć program przed możliwością niezgodności wymiarów. Do określenia liczby wątków wykorzystać metodę Runtime.getRuntime().availableProcessors(). Zmierzyć czas mnożenia dużych macierzy (wymiaru co najmniej 3000×3000 elementów) za pomocą metody klasycznej oraz wielowątkowej. W tym celu wykorzystać obiekty klasy Date() oraz metode getTime().