CodeGym /Kursy /JAVA 25 SELF /Wprowadzenie do wielowątkowości: po co jest potrzebna

Wprowadzenie do wielowątkowości: po co jest potrzebna

JAVA 25 SELF
Poziom 51 , Lekcja 0
Dostępny

1. Czym jest wątek wykonania (thread)

Wątek jako samodzielna linia pracy

W Javie (i w programowaniu ogólnie) wątek wykonania — to niezależna sekwencja poleceń, która biegnie równolegle z innymi wątkami w ramach jednego programu. Wyobraź sobie fabrykę: każda szwaczka ma własne stanowisko i zadanie, pracuje niezależnie, ale wszystko razem składa się na wspólny rezultat.

Domyślnie program w Javie startuje z jednym wątkiem — tym, który uruchamia metodę main. Nic jednak nie stoi na przeszkodzie, aby tworzyć dodatkowe wątki, by różne części programu wykonywały się jednocześnie.

Procesy i wątki: jaka jest różnica?

  • Proces — to „ciężka” jednostka wykonania. Każdy proces ma własną przestrzeń pamięci, własne zmienne, własne zasoby. Procesy są całkowicie odizolowane od siebie — jeśli jeden „padnie”, pozostałe nie ucierpią.
  • Wątek (thread) — to „lekka” jednostka wykonania wewnątrz procesu. Wszystkie wątki jednego procesu współdzielą pamięć i zasoby. Oznacza to, że mogą łatwo wymieniać się danymi (i, niestety, równie łatwo mogą sobie przeszkadzać).

Analogia:
Proces — to oddzielne mieszkanie: każde ma własne ściany i lokatorów.
Wątki — to lokatorzy w jednym mieszkaniu: każdy ma swoje sprawy, ale kuchnia i łazienka są wspólne.

Jak to wygląda w Javie?

Kiedy uruchamiasz program, JVM tworzy co najmniej jeden wątek — główny (main). Możesz jednak tworzyć kolejne wątki, aby wykonywać zadania równolegle.

2. Po co nam wielowątkowość

Responsywność: UI nie powinien się „zawieszać”

Załóżmy, że piszesz program z interfejsem graficznym — na przykład edytor tekstu. Użytkownik kliknął przycisk „Zapisz”, a ty zaczynasz długo i żmudnie zapisywać plik na dysk. Jeśli wszystko to dzieje się w wątku głównym, okno programu się „zamrozi”: użytkownik nie może nic kliknąć, kursor się nie porusza, interfejs nie reaguje. Jeśli jednak zapis wykonasz w osobnym wątku — interfejs pozostanie responsywny, a użytkownik będzie mógł nawet się rozmyślić i zamknąć program.

Przykład z życia:
Otwierasz przeglądarkę i zaczynasz pobierać duży plik. Gdyby przeglądarka nie używała wątków, nie mógłbyś otworzyć nowej karty ani przewinąć strony, dopóki plik by się nie pobrał!

Równoległe przetwarzanie danych

Masz listę tysiąca plików do przetworzenia (np. przeliczenie hashy lub zamiana tekstu). Dlaczego nie zrobić tego równolegle? Każdy wątek bierze swój plik i pracuje nad nim niezależnie, a całość kończy się kilka razy szybciej.

Przykład:
Serwer obsługuje żądania od setek klientów. Gdyby serwer robił to w jednym wątku, pozostali klienci czekaliby na swoją kolej w nieskończoność. Z wątkami każde żądanie jest obsługiwane niezależnie!

Wykorzystanie procesorów wielordzeniowych

Współczesne procesory — to nie jeden „mózg”, lecz cały zespół (rdzenie), który może pracować równolegle. Jeśli twój program używa tylko jednego wątku, pozostałe rdzenie się nudzą i grają w Sapera. Jeśli uruchamiasz kilka wątków — wszystkie rdzenie mają co robić, a program działa szybciej.

Ciekawostka:
Nawet twój telefon ma kilka rdzeni, a laptopy i serwery — dziesiątki! Nie wykorzystywać ich wszystkich — to jak kupić autobus i jeździć nim w pojedynkę.

3. Przykłady z życia

Dziedzina Przykład wielowątkowości
Pobieranie plików Pobieranie kilku plików jednocześnie
Interfejs użytkownika (UI) Aplikacja nie „wiesza się” podczas ładowania/zapisywania danych
Serwery Równoległa obsługa wielu żądań sieciowych
Gry Oddzielne wątki dla fizyki, grafiki, muzyki, AI
Komunikatory Odbieranie wiadomości, wysyłanie plików, odświeżanie interfejsu
Przetwarzanie wideo Równoległe przetwarzanie klatek

Krótka analogia:
Kucharz gotuje zupę, równocześnie piekarnik piecze ciasto, a robot sprzątający odkurza podłogę — wszystko dzieje się jednocześnie, więc kolacja powstaje szybciej!

4. Potencjalne trudności wielowątkowości

Warunek wyścigu (race condition)
Gdy kilka wątków jednocześnie zmienia tę samą zmienną, wynik może być nieprzewidywalny. Na przykład, jeśli dwa wątki równocześnie zwiększają wspólny licznik, wartość końcowa może być nieprawidłowa. O tym porozmawiamy szerzej w jednej z kolejnych lekcji.

Synchronizacja
Aby wątki sobie nie przeszkadzały, trzeba wymyślić sposoby „dogadania się” — kto i kiedy może zmieniać dane. To nazywa się synchronizacją. Służą do tego specjalne słowa kluczowe i konstrukcje (synchronized, blokady itp.), o których porozmawiamy później.

Deadlock (wzajemna blokada)
Czasem wątki mogą się tak „zaprzyjaźnić”, że będą czekać na siebie w nieskończoność i program się zawiesi. To nazywa się deadlock — i jest jedną z najbardziej podstępnych pomyłek w programowaniu wielowątkowym.

Debugowanie i testowanie
Błędy w programach wielowątkowych bardzo trudno wyłapać: czasem wszystko działa, a czasem — nie. Bywa, że błąd ujawnia się tylko na serwerze albo u użytkownika, a u ciebie na komputerze wszystko jest idealnie. To sprawia, że testowanie i debugowanie kodu wielowątkowego jest dla programisty prawdziwym wyzwaniem.

5. Krótki przegląd: jak wygląda program wielowątkowy

Przykład bez wątków:

public class Main {
    public static void main(String[] args) {
        // Liczymy do 5
        for (int i = 1; i <= 5; i++) {
            System.out.println(i);
        }
        // Wypisujemy litery
        for (char c = 'A'; c <= 'E'; c++) {
            System.out.println(c);
        }
    }
}

Wyjście zawsze jest takie samo:

1
2
3
4
5
A
B
C
D
E

Przykład z wątkami:

public class Main {
    public static void main(String[] args) {
        Thread numbers = new Thread(() -> {
            for (int i = 1; i <= 5; i++) {
                System.out.println(i);
                try {
                    Thread.sleep(100); // Chwilę poczekamy
                } catch (InterruptedException e) {
                    // Ignorujemy
                }
            }
        });

        Thread letters = new Thread(() -> {
            for (char c = 'A'; c <= 'E'; c++) {
                System.out.println(c);
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    // Ignorujemy
                }
            }
        });

        numbers.start();
        letters.start();
    }
}

Wyjście będzie przemieszane:

1
A
2
B
3
C
4
D
5
E

albo, jeśli wątki „rywalizują”, kolejność może być inna. Najważniejsze — obie pętle wykonują się równolegle!

6. Przydatne niuanse

Schemat wizualny: jak wątki współpracują

+-------------------+     +-------------------+
|    Główny wątek   |     |    Drugi wątek    |
+-------------------+     +-------------------+
| 1 | 2 | 3 | 4 | 5 |     | A | B | C | D | E |
+-------------------+     +-------------------+
        |                         |
        |   Oba działają          |
        |   jednocześnie          |
        +-------------------------+

Gdzie Java używa wątków „pod maską”

  • Zbieranie śmieci (Garbage Collector) — osobny wątek czyści nieużywane obiekty.
  • Wejście/wyjście (I/O) — odczyt i zapis plików, połączenia sieciowe.
  • Serwery i aplikacje webowe — każde żądanie klienta jest obsługiwane w osobnym wątku.
  • Timery, harmonogramy zadań — wykonywanie zadań zgodnie z harmonogramem.

7. Typowe błędy początkujących

Błąd nr 1: Oczekiwanie, że wątki zawsze przyspieszają program.
W rzeczywistości, jeśli masz jednoprocesorową maszynę albo źle zorganizujesz pracę, wielowątkowość może tylko spowolnić wykonanie z powodu „zamieszania” i narzutu na przełączanie się między wątkami.

Błąd nr 2: Ignorowanie problemów synchronizacji.
Wielu uważa: „Przecież tylko uruchamiam dwa wątki, co może pójść nie tak?” Jednak jeśli oba wątki zmieniają jedną zmienną, wynik może być całkowicie nieoczekiwany.

Błąd nr 3: Używanie wątków do wszystkiego.
Nie warto uruchamiać osobnego wątku dla byle drobiazgu. Wątki to zasób, a ich nadmierna liczba może prowadzić do spowolnień, a nawet do awarii programu.

Błąd nr 4: Brak obsługi błędów.
Wątki mogą wyrzucać wyjątki (np. przy pracy z plikami lub siecią). Jeśli nie obsłużysz tych błędów, program może zakończyć się awaryjnie albo „zawiesić”.

Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION