watki











Wątki (threads)

Programy pisane za pomocą języków C czy Pascal, składają się ogólnie
mówiąc z pojedynczego, głównego modułu wykonywanego linia po linii. Java
podobnie jak inne nowoczesne systemy operacyjne obsługuje wielozadaniowosć
(w przypadku Javy chodzi o wilowątkowosć, multithreading), czyli możliwosć
jednoczesnego uruchamiania oddzielnych modułów programu oraz ich dalszego
równoległego działania.

Klasyczny, jednowątkowy program wykonywany jest przez procesor w sposób
liniowy - instrukcja po insrukcji. W przypadku wystąpienia w nim operacji,
które z różnych przyczyn przebigają relatywnie wolno (na przykład proces
drukowania rysunku, oczekiwanie na podanie przez użytkownika jakis danych),
korzystniej by łoby gdyby zostały one przesunięte na dalszy plan (były
wykonywane w tle). W tym czasie procesor zająłby się innymi, nie cierpiącymi
zwłoki zadaniami (jak na przykład wykonywaniem obliczeń czy odswierzaniem
ekranu).

Najlepszym wyjsciem byłoby jednoczesne wykonywanie dwóch zcy nawet więcecej
modułów programu (wątków). Jeden z nich mógłby na przykład przejąć zadanie
drukowania, podczas gdy inny byłby odpowiedzialny za przyjmowanie od użytkownika
danych, a kolejny za wykonywanie odpowiednich obliczeń. Co prawda w zasadzie
taka równoległosć działań jest możliwa do uzyskania bez "wielozadaniowosci",
jednak osiągnięcie tego efektu kosztuje dosć dużo pracy. Wielowątkowosć
jest jedną z cech Javy dlatego wiele problemów związanych z tym zagadnieniem
przestaje istnieć.

Możliwosć równoległego uruchamiania kilku wątków nie oznacza jednak
jeszcze, że system wyposażony tylko w jeden procesor rzeczywiscie będzie
w stanie wykonywać więcej niż jedno działanie jednoczesnie. De facto chodzi
jedynie o wykonywanie kilku linijek kodu danego wątku. Tak zwany scheduling
(przełączanie zadań) odpowiedzialny jest za przydzielanie każdemu wątkowi
odpowiedniej ilosci czasu obliczeniowego procesora, tak by sprawiać wrażenie
rownoległosci wykonywania.

Ponadto poszczególnym wątkom mogą być przypisane różne priorytety, które
decydują o kolejnosci przydzielania im czasu obliczeniowego. Służy do tego
funkcja "setPriority()", której parametr musi miescić się w przedziale
od MIN_PRIORITY do MAX_PRIORITY. Im mniejsza jest jego wartosć, tym dłużej
wątek będzie czekałna swoją kolej. Wątki o takim samym priorytecie obsługiwane
będą jędnoczenie.

Istnieją dwie możliwosci tworzenia wątków. Po pierwsze poprzez utworzenie
klasy pochodnej zawierającej kod wątku od klasy "Thread". W poniższym
przykładzie gry w kosci utworzone zostały dwa typy wątków . "WatekGracza"
obrazuje zachowanie graczy i "CzasGry" odpowiedzialny za odmierzanie
czasu trwania gry - z każdą sekundą będzie zwiększał odpowiedni licznik.
Klasa "Gra" zawiera procedurę "main()". W pierwszej
kolejnosci utworzone zostaną one uaktywnione (wywolania: "Tomasz.start()"
oraz "Jerzy.start()"). Po upływie dziesięciu sekund, gra zostanie
zakończona, a otrzymany rezultatpoddany ocenie.


public class Gra
{
static boolean GraAktywna=true;

public static void main(String args[])
{
// tworzenie wątków (-> stan gry "New" ...)
WatekGracza Tomasz=new WatekGracza("Tomasz");
WatekGracza Jerzy=new WatekGracza("Jerzy");

//... uruchomienie wątków (-> stan gry "Runnable")
Tomasz.start();
Jerzy.start();

// uruchomienie zegara odmierzającego czas trwania gry
new CzasGry().start();
while (CzasGry.Sekundy < 10)
{// gra zakończona
GraAktywna=false;
}

// podanie wyniku
System.out.println("Punkty uzyskane przez Tomasza: "+Tomasz.Punkty+" / Jerzego: "+Jerzy.Punkty);
if (Tomasz.Punkty > Jerzy.Punkty)
System.out.println("Wygrał Tomasz");
else
System.out.println("Wygrał Jerzy");
}
}

class WatekGracza extends Thread
{
// liczba punktów osiągniętych przez gracza
public int Punkty;

// konstruktor wątku
public WatekGracza (String ImieGracza)
{
// konstruktor klasy bazowej wywoływany jest przez nazwę wątku
super(ImieGracza);
}

public void run()
{
int Rzut; // wynik rzutu
while (Gra.GraAktywna)
{
// rzut kośćmi
Rzut=(int)(Math.random()*6); // funkcja random z pakietu java.util

// zwiększenie liczby punktów o uzyskany wynik rzutu
Punkty+=Rzut;

// podanie wyniku rzutu
System.out.println(getName()+" wyrzucił "+Rzut+"oczek - liczba punktów"+Punkty);

// im gorszy wynik rzutu, tym dłużej gracz musi czekać na swoją kolej
// (jeden gracz może rzucać kilakrotnie pod rząd)
try
{
sleep ((long)(6-Rzut)*100);
}
catch (InterruptedException e)
{
// wyjątek ten zostanie usunięty kiedy bieżący potok zostanie przerwany przez inny.
// Niniejsza instrukcja catch musi tu zostać zaimplementowana,
// w przeciwnym razie kompilator zgłosi komunikat o błędzie.
System.out.println("Wyjątek");
}
}
}
}

class CzasGry extends Thread
{
static int Sekundy=0;

public void run()
{
while (Gra.GraAktywna)
{
try {sleep(1000);}
catch (InterruptedException e) {}
Sekundy+=1;
}
}
}


Metoda "run()" klasy "WatekGracza" opisuje właściwą
część gry: Każdy z graczy może rzucać koscmi. osiągnięta liczba oczek dodawana
jest do ogólnej liczby puktów danego gracza. Im jest wyższa, tym krócej
dany wątek znajduje się w stanie "uspienia" (instrukcja "sleep()"
umożliwia ustawiene potoku w stan bezczynnosci na okreslony, podawany w
milisekundach czas). W przypadku uzyskania "6" gracz może natychmiast
rzucać dalej. Po dziesięciu sekundach sędzia (funkcja "main()")
konczy grę (ustawiając "GraAktywna = false"). Jesli utworzonych
zostało kilku graczy, grają oni przeciwko sobie. ponieważ zależnie od uzyskiwanej
liczby oczek wzajemnie przenoszą się oni w stan uspienia, każdy z nich,
zależnie od uzyskiwanych rezultatów może rzucać kilka razy pod rząd. Za
każdym razem podawana jest liczba uzyskiwanych przez gracza oczek oraz
ogólna liczba zdobytych przez niegodo tej pory punktów. Użycie funkcji
"sleep()" wymusza stworzenie metody obsługi wyjątku "InterruptedException",
ponieważ nie jest to wyjątek typu runtime-exception i jesli nie zostanie
przechwycony interpreter Javy przerwie wykonanie programu w momencie, w
którym się on pojawi. Wyjątek ten występuje w chwili, gdy jeden wątekjest
zatrzymywany, a uaktywniany inny (przełączanie zadań).

Identyfikacja gracza odbywa się za posrednictwem nazwy odpowiadającego
mu wątku. Konstruktor klasy "WatekGracza" otrzymuje tę nazwę
jako parametr. Za posrednictwem wywołania "super()" przewkazuje
ją dalej, do konstruktora klasy bazowej. Z kolei "getName()"
podaje nazwę potoku, który jest aktualnie aktywny.

Druga możliwosć polega na utworzeniu klasy wątku implementującej interfejs
"Runnable". Każda klasa, która implementuje ten interfejs musi
implementować własną metodę "run()". W celu uruchomienia takiego
wątku należy więc najpierw stworzyć obiekt tej klasy, a potem utworzyć
wątek (obiekt klasy "Thread"). Konstruktor klasy "Thread",
któremu należy przekazać nasz obiekt i staje sie on odpowiedzialny za przeprowadzenie
wszelkich koniecznych inicjalizacji. Na koniec w celu uruchomienia wątku
należy wywołać metodę "start()". Definicja przykładowego wątku
może więc wyglądać następująco:


class DemoThread implements Runnable
{
public void run() // zadaniem wątku jest odliczenie od 1 do 10
{
int i;
for (i=0; i

Wyszukiwarka

Podobne podstrony:
wątki ceglane pśin
SO 05 Watki
watki
opis watki (2)
Wątki mitologiczne w sztuce nowożytnej
opis watki
watki
Java watki
sołtys,systemy operacyjne, wątki
wyk watki mutexy
watki 2
wątki
Wątki
Wątki
watki

więcej podobnych podstron