6. Wą tki.

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. Wą tki.

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. Wą tki.

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

6. Wą tki.

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

6. Wą tki.

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

6. Wą tki.

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

6. Wą tki.

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

6. Wą tki.

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

6. Wą tki.

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

6. Wą tki.

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. Wą tki.

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

6. Wą tki.

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

6. Wą tki.

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

6. Wą tki.

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

6. Wą tki.

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

6. Wą tki.

}

}

// 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

6. Wą tki.

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

6. Wą tki.

3) "Cykl Ŝycia" wątku

yield

start

Nowo utworzony

Wykonywany

Zablokowany

Zakoń czenie metody run()

Zakończony

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();

}

W. Kasprzak: Programowanie zdarzeniowe

6 - 18

6. Wą tki.

}

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

6. Wą tki.

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

6. Wą tki.

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

6. Wą tki.

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

6. Wą tki.

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. Wą tki.

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

6. Wą tki.

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

6. Wą tki.

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

6. Wą tki.

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

6. Wą tki.

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

6. Wą tki.

}

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

6. Wą tki.

}

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

6. Wą tki.

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. Wą tki.

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

6. Wą tki.

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

6. Wą tki.

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

6. Wą tki.

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

6. Wą tki.

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

6. Wą tki.

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

6. Wą tki.

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

6. Wą tki.

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