opublikował: Teo-TN, 2014-01-02

 

Wprowadzenie do tematu

Jak wiele narzędzi programistycznych, wątki zostały wprowadzone do języka JAVA w odpowiedzi na konkretny problem. Bardzo często zdarza się, że tworzony przez nas program musi na coś poczekać. Może to być oczekiwanie na pobranie pliku z Internetu, na wykonanie skomplikowanej operacji matematycznej na zdalnym urządzeniu, na dostęp do bazy danych, czy nawet oczekiwanie na reakcję użytkownika.

 

Jeżeli pomyślimy o programie jako jednym wątku, czyli jednym ciągu operacji następujących jedna po drugiej, niezależnie od stanu programu, to okaże się, że bardzo dużo czasu jest traconego na oczekiwanie. Jako przykład weźmy przeglądarkę internetową. Czy byłaby to Twoja ulubiona przeglądarka, drogi Czytelniku, gdyby nie można było jednocześnie pobierać pliku oraz przeglądać kilku kolejnych stron internetowych? Zapewne nie. Właśnie tutaj do gry wchodzą wątki.

 

Równoległość a współbieżność

Wątki, czyli wyodrębnione serie działań, mogą być realizowane na dwa sposoby: równoległy oraz współbieżny. Kiedy mówimy o działaniu równoległym, mamy na myśli, że dwa zadania są wykonywane jednocześnie. Aby to osiągnąć, trzeba je rozdzielić pomiędzy różne jednostki obliczeniowe, przykładowo możemy myśleć, że jeden procesor (lub rdzeń) zajmuje się obliczaniem kąta odbicia piłki (lub, aby była to rzecz bardziej pracochłonna, miliona piłek) od ściany, podczas gdy drugi przetwarza informacje związane z wyświetlaniem grafiki reprezentującej tą piłkę.

 

Podejście takie może jednak okazać się zbyt kosztowne, ponieważ w pewnym momencie ilość zadań może być tak znaczna, że nie opłaca się dokupować kolejnych procesorów do jej realizacji.

 

Innym rozwiązaniem problemu jest użycie współbieżności. Jest to model, w którym wątek otrzymuje do dyspozycji moc obliczeniową procesora (a raczej jej część) tylko na jakiś niewielki czas, po czym pewien zarządca wątków wybiera inny wątek, który zacznie działać, ponownie, tylko na jakiś czas.

 

Dzięki współbieżności nasza przeglądarka może działać na pojedynczym procesorze z jednym rdzeniem: rozpoczynamy pobieranie pliku i zanim ów plik się pobierze następuje oczekiwanie, w trakcie którego inny wątek „dochodzi do głosu”, więc można nawiązać połączenie z ulubioną stroną internetową i przeglądać jej treść, zaś po zakończeniu pobierania znów na chwilę zostanie wywołany odpowiedni wątek, by wyświetlić informację o zakończeniu pobierania. – Oczywiście jest to znaczne uproszczenie.

 

Jak tworzyć wątki?

Istnieje kilka sposobów, by utworzyć wątek. Najprostszym z nich jest utworzenie klasy dziedziczącej po klasie Thread:

public class Watek extends Thread {

    static int id = 0;

    public Watek() {

         super(“Watek numer: “ + String.valueOf(id++) );

    }

    public void run() {
    
        //tutaj następuje realizacja zadania wątku

    }

}

Zaś uruchomienie tego wątku następuje poprzez wywołanie odpowiedniej metody, na obiekcie tej klasy:

Watek w1 = new Watek();

w1.start();

Innym podejściem jest wykorzystanie interfejsu Runnable. Podejście to jest często stosowane, m.in. ze względu na to, że JAVA nie wspiera wielodziedziczenia, czy też dlatego, że chcemy utrzymać stałą ilość wątków, które dostaną różne zadania do realizacji:

public class Zadanie implements Runnable {

    static int id = 0;

    int myId;

    public Zadanie() {

        myId = id;

        id++;

    }

<span style="\\&quot;font-family:" arial,="" verdana,="" sans-serif;\\"="">          public void run() {

    System.out.println(myId);

    }

}

Przydzielenie takiego zadania do wątku może się odbywać następująco:

Zadanie[] zadania = new Zadanie[5];

Thread[] watki = new Thread[5];

//Stwórzmy 5 obiektów-zadań:

for (int i=0; i<5; i++) {

                zadania[i] = new Zadanie();

}

//Tworzenie 5 wątków, które jako argument konstruktora przyjmują zadanie

for (int i=0; i<5; i++) {

                watki[i] = new Thread(zadania[i]);

}

//Wywołanie zadań

for (int i=0; i<5; i++) {

                watki[i].start();

}

Istotnym tutaj jest podkreślenie, że realizacja zadań nie nastąpi w kolejności utworzenia/wywołania wątków! Oczywiście, może się zdarzyć, że tak właśnie nastąpi, ale ważne jest, by podkreślić, że nie jest to regułą. Po zaimplementowaniu powyższego kodu w funkcji main oraz uruchomieniu programu możemy zobaczyć w konsoli przykładowo:

0

2

3

4

1

 

zaś przy kolejnym uruchomieniu, również przykładowo:

1

2

0

3

4
Zaloguj się aby dodać komentarz