Temat: Wątki
Czym są wątki. Grafika. Proste animacje. Małe podsumowanie materiału.


Na podstawie: Arnold, Gosling; Boone; Eckel.

1 Wątki

Zwykłe operacje w programach komputerowych są wykonywane sekwencyjnie, tzn. kolejno, jedna po drugiej. Są to tzw. programy jednowątkowe. JavaTM stwarza możliwość wykonywania programu wielowątkowo. Wątki mogą przy tym korzystać i modyfikować te same zasoby danych. Wymaga to koordynacji przebiegu poszczególnych wątków. Wątki nie mogą przeszkadzać sobie nawzajem i dostęp do zasobów przez poszczególne wątki nie powinien odbywać się chaotycznie. Mechanizmy obsługi wątków są w JavaTM wysoko wyspecjalizowane. Są to blakady zasobów, odpytywanie itp.

2 Tworzenie wątków

Wątki w JavaTM udostępnia klasa Thread. Wątek tworzymy poleceniem -
   Thread przebieg = new Thread();
Następnym krokiem jest konfiguracja utworzonego wątku. Można go nazwać, nadać mu priorytet początkowy i następnie wykonać uruchamiając metodę start() wątku. Tak uruchomiony wątek wykonuje następnie metodę run(). Po wykonaniu tej metody wątek ginie. Wątek można też zatrzymać uruchamiając metodę stop() wątku. Metoda sleep(milis) usypia wątek na milis milisekund. Poniższy przykład pochodzi z podręcznika Arnolda i Goslinga, JavaTM .
//
// K. Arnold, J. Gosling, Java
// PingPong.class; 
// Wątki
//
class PingPong extends Thread {
    String word;// co wypisać
    int delay;
    PingPong(String whatToSay, int delayTime) {
        word  = whatToSay;
        delay = delayTime;
    }
    public void run() {
        try {
            for (;;) {
                System.out.print(word + " ");
                sleep(delay);    // czekaj na nastepna kolejke
            }
        } catch (InterruptedException e) {
            return;              //  zakoncz ten watek
        }
    }
    public static void main(String[] args) {
        new PingPong("ping", 33).start();    // 1/30 sec
        new PingPong("PONG",100).start();    // 1/100 sec
    }
}
(Program do pobrania: jpgm/PingPong) Klasa PingPong jest potomkiem klasy Thread. Konstruktor obiektów tej klasy ustawia dwie zmienne. Jedna z nich to word, zawierająca dowolny napis (tutaj ping lub PONG), a druga jest czasem który wątek przesypia, a więc jest nieaktywny. Metoda main deklaruje dwa wątki i uruchamia je. Jeden z nich (ping) budzi się co 33/1000 ms, a drugi (PONG) co 1/10 ms. Pilnuje tego metoda run() wątku, która zatrzymuje go na ten czas wywołując metodę sleep(delay) z parametrem delay, określającym liczbę przesypianych milisekund. Wynik programu będzie podobny do następujacego.
ping PONG ping ping ping PONG ping ping ping PONG ping ping
ping PONG ping ping ping PONG ping ping ping PONG ping ping
ping PONG ping ping ping PONG ping ping ping PONG ping ping
ping PONG ping ping ping PONG ping ping ping PONG ping ping
PONG ping ping ping PONG ping ping ping PONG ping ping ping
PONG ping ping ping PONG ping ping ping PONG ping ping ping
PONG ping ping ping PONG ping ping ping PONG ping ping ping
PONG ping ping ping PONG ping ping ping PONG ping ping ping
PONG ping ping PONG ping ping ping PONG ping ping PONG ping
ping PONG ping ping PONG ping ping PONG ping ping ping PONG
ping ping ping PONG ping ping ping PONG ping ping ping PONG
ping ping ping PONG ping ping ping PONG ping ping ping PONG
Widzimy, że napisy ping i PONG różnią się częstością występowania. Metoda setName nadaje nazwę wątkowi, a getName odczytuje ją. Nazwą można też nadać przekazując konstruktorowi wątku obiekt klasy String.

3 Synchronizacja

Metody JavaTM mogą być synchronizowane (synchronized). Jeśli jakiś wątek wykonuje taką metodę dla danego obiektu, to wchodzi jednocześnie do tzw. monitora obiektu i wszystkie inne wywołania metod synchronizowanych dla tego obiektu muszą czekać, aż wątek opuści monitor. Dzieje się to wtedy gdy metoda synchronizowana zakończy się. Synchronizacja wymusza wzajemne wykluczanie wykonywania sie wątków w tym samym czasie.
P r z y k ł a d 1. Poniższa metoda zamienia wszystkie elementy tablicy na dodatnie, zastępując wszystkie ujemne elementy ich wartością bezwzględną. Fragment tej metody musimy synchronizować po to, by żaden inny wątek oprócz wątku aktualnie wywołującego metode nie mógł przypadkowo zmienić już zmienionych danych.
// zamień wszystkie elementy tablicy na nieujemne
// Arnold, Gosling
public static void abs(int[] values) {
    synchronixed (values) {
        for(int i = 0; i < values.length; i++) {
            if(values[i] < 0)
                values[i] = -values[i];
        }
    }
}
Operacje na elementach tablicy są synchronizowane. Dopiero po wykonaniu całej pętli obiekt zajęty przez wątek zostaje zwolniony. Mamy pewność, że cała tablica została przebadana i żaden inny przypadkowy proces nie zmienił jej zawartości.
Dwie metody wait i notify, zdefiniowane w klasie Object, pozwalaja na dodatkową komunikację między wątkami. Metoda wait każe wątkowi czekać, aż jakieś wydarzenie zostanie zrealizowane, a metoda notify informuje o tym fakcie. Schemat, wg. którego stosuje się metodę wait pokazany jest niżej.
synchronized void wykonajWarunkowo() {
    while( !warunek)
        wait();
        
        ... kod do wykonania po spełnieniu warunku
}
Nie będziemy tu omawiać problemów tzw. zakleszczania wątków, licząc na to, że nasze programy nie będą zbyt złożone.

4 Dodatki

Wątki można zawieszac (suspend). Jest to przydatne gdy chcemy by działały one w pewnych tylko chwilach, a więc wtedy, gdy potrzeba. Elegancki sposób zatrzymywania wątku polega nie na jego przerwaniu metodą stop, lecz inaczej. Zazwyczaj w metodzie run sprawdza się jakąś zmienna logiczną, której wartość może się zmieniać w zależności od warunków.

5 Algorytmy sortowania

Klasycznym już przykładem ilustrującym trzy algorytmy sortowania, zrealizowanym w JavaTM pokazana w ilustracjach dystrybucji Java SDK 2. (patrz jdk1.3//demo//applets//SortDemo).

The Sorting Algorithm Demo (1.1)


                 Bi-Directional
Bubble Sort        Bubble Sort      Quick Sort
alt="Your browser understands the <APPLET> tag but isn't running the applet, for some reason."Your browser is completely ignoring the <APPLET> tag!     alt="Your browser understands the <APPLET> tag but isn't running the applet, for some reason."Your browser is completely ignoring the <APPLET> tag!     alt="Your browser understands the <APPLET> tag but isn't running the applet, for some reason."Your browser is completely ignoring the <APPLET> tag!

The Sources

The applet.
The "generic" sorting algorithm.
The Bi-directional Bubble Sort algorithm.
The Bubble Sort algorithm.
The Quick Sort algorithm.

6 Klasa Runnable

Oprócz klas, JavaTM dostarcza tzw. interfejsów (sprzęg). Interfejs stanowi typ składający sie tylko z metod abstrakcyjnych oraz stałych. Interfejs jest przykładem czystej formy projektu, klasy zaś są mieszanką projektu i implementacji (Arnold, Gosling). Klasy mogą implementować metody interfejsu tak, jak chce programista. W ten sposób interfejs ma dużo więcej możliwych implementacji niż klasa. Klasa może implementowac wiele interfejsów naraz. Jednym z interfejsów JavaTM jest Runnable. Runnable deklaruje jedną metodę: -
   public void run();
Oto jak wyglada program PingPong (teraz RunPingPong), gdzie zastosowano interfejs Runnable.
//
// K. Arnold, J. Gosling, Java
// PingPong.class; 
// Wątki
//
class RunPingPong implements Runnable {
    String word;// co wypisać
    int delay;                  // ile czekać
    RunPingPong(String whatToSay, int delayTime) {
        word  = whatToSay;
        delay = delayTime;
    }
    
    public void run() {
        try {
            for (;;) {
                System.out.print(word + " ");
                sleep(delay);    // czekaj na nastepna kolejke
            }
        } catch (InterruptedException e) {
            return;              //  zakoncz ten watek
        }
    }
    public static void main(String[] args) {
        Runnable ping = new RunPingPong("ping", 33);
        Runnable pong = new RunPingPong("PONG",100);
        new Thread(ping).start();
        new Thread(pong).start();
    }
}
(Program do pobrania: jpgm/RunPingPong) Tworzone obiekty (ping i pong) klasy Thread są uruchamiane poprzez wywołanie metody start(). Wynik działania programu jest podobny do poprzedniego.

7 Pewne uzupełnienia

Podamy kilka konstrukcji JavaTM , znanych (lub podobnych) do odpowiednich konstrukcji programistycznych C++ lu Pascala.

7.1 Przepływ sterowania

if (boolean) instrukcja
else instrukcja
switch(zmienna) {
  case wartość: instrukcja
  case wartość: instrukcja
  ...
  default: instrukcja
}
break [etykieta]
continue [etykieta]
return [wartość]
for([wartość_początkowa];[warunek_zakończenia];[wartość_końcowa])
   [instrukcja]
   
   
while (boolean) instrukcja
do instrukcja while (boolean)
etykieta: instrukcja
boolean ? wynik_gdy_prawda : wynik_gdy_fałsz

7.2 Układacze

Aplet lub okno można wyposażyć w różne elementy, jak przyciski (Button), pola tekstowe (TextField), etykiety (Label) itd. Układamy je w pojemnikach. W JavaTM czynią to specjalne układacze. Są to
FlowLayout - standardowy ukladach w apletach
BorderLayout
CardLayout
GridLayout
GridBagLayout
FlowLayout. Dodaje elementy do pojemnika od lewej strony do prawej, wyśrodkowując każdy z nich w pionie. Ułożeniem sterują parametry: LEFT, CENTER, RIGHT. BorderLayout. Umieszcza elementy w pozycjach North, South, West, East i Center.
|   ...
|   setLayout(new BorderLayout());  // wybierz układacz
|   resize(400, 200);                // ustaw rozmiar okna
|   textF = new TextField(6);
|   add("North", textF);
|   label = new Label("Etykieta");
|   add("South", label);
|   ...
GridLayout. Elementy umieszczane są w siatce o jednakowych oczkach, kolejno od lewej strony do prawej.
|   setLayout(new GridLayout(1,2));
    +------------------------------+
    |  | element|   | element |    |
    +------------------------------+
|   setLayout(new GridLayout(2,1));
    +---------------+
    |  | element|   |
    |               |
    |  | element|   |
    +---------------+
    
W tym miejscu nie będziemy mówić o słuchaczach oraz adapterach. Wyposaża się w nie elementy by reagowały na zdarzenia takie jak np. ruch myszki, naciśnięcie przycisku myszy, naciśnięcie klawisza i setki innych.
Z a d a n i e 1. Należy przeczytać, np. w www.javasoft.com [ http://www.javasoft.com ] o elementach graficznych (TextField, Label, CheckBox, RadioButton, DropDownList) oraz o starych metodach obsługi zdarzeń (action(), handleEvent(), actionListener(), ...) i nowych odpowiednikach w JDK 2.
P r z y k ł a d 2. Procedura handleEvent().
...
Button b1 = new Button("Guzik1");
Button b2 = new Button("Guzik2");
...
public boolean action(Event e, Object o) {
    if(e.target.equals(b1))
        getAppletContext().showStatus("Guzik 1");
    else if(e.target.equals(b2))
        getAppletContents().showStatus("Guzik 2");
    else return super.action(e, arg);
    return true;
}

8 Małe podsumowanie

Na podstawie: Boone

Zbierzemy najważniejsze informacje o JavaTM . Jeśli czegoś nie rozumiesz, szukaj w podręcznikach.

8.1 Definicje klas

8.2 Słowa kluczowe dla klas i zmiennych

8.3 Typy proste

8.4 Wartości i zmienne

8.5 Wyjątki

8.6 Tworzenie obiektów i sprawdzanie

8.7 Sterowanie