programowanieProgramista Java

Czym jest wątek (thread) w Javie, jak odbywa się ich tworzenie i zakończenie oraz jakie szczegóły warto uwzględnić przy realizacji programów wielowątkowych?

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź.

Historia pytania:

W Javie wsparcie dla wielowątkowości zostało wprowadzone od samego początku. Wątki pozwalają na jednoczesne wykonywanie kilku zadań, efektywnie wykorzystując procesory wielordzeniowe. JVM zapewnia warstwę abstrakcji nad wątkami systemu operacyjnego.

Problem:

Tworzenie, zarządzanie i zakończenie wątków wymaga jasnego zrozumienia ich cyklu życia, synchronizacji oraz możliwych stanów wyścigu. Nieostrożne użycie wątków może prowadzić do deadlocków, niepoprawnego dostępu do zasobów oraz skomplikowanych logów błędów.

Rozwiązanie:

W Javie wątki można tworzyć przez rozszerzenie klasy Thread lub implementację interfejsu Runnable, a także przy użyciu nowoczesnych narzędzi typu ExecutorService. Ważne jest poprawne zakończenie wątków, zarządzanie ich cyklem życia oraz synchronizacja dostępu do danych współdzielonych.

Przykład tworzenia i zakończenia wątku:

class MyRunnable implements Runnable { public void run() { System.out.println("Wątek działa"); } } public class ThreadExample { public static void main(String[] args) { Thread t = new Thread(new MyRunnable()); t.start(); // uruchomienie wątku try { t.join(); // oczekiwanie na zakończenie } catch (InterruptedException e) { e.printStackTrace(); } } }

Kluczowe cechy:

  • Wątki należy uruchamiać metodą start(), a nie run() (w przeciwnym razie nie będzie rzeczywistego równoległego przetwarzania)
  • Dla poprawnego zakończenia ważne jest użycie join()
  • Nie można ponownie uruchomić zakończonego wątku: nowe wywołanie start spowoduje IllegalThreadStateException

Pytania z pułapką.

Czy można ponownie uruchomić wątek po jego zakończeniu?

Nie. Po zakończeniu wątek uznawany jest za "martwy", ponowne wywołanie start() spowoduje IllegalThreadStateException.

Jaka jest różnica między wywołaniem t.run() a t.start()?

t.run() po prostu wywoła metodę run w bieżącym wątku, nie tworząc nowego wątku wykonawczego. Tylko t.start() tworzy oddzielny wątek systemu operacyjnego.

Co się stanie, jeśli wątek zakończy się z nieobsłużonym wyjątkiem?

Jeśli zostanie zgłoszony nieobsłużony wyjątek, wątek zakończy się awaryjnie, jego stos śladowy zostanie wyświetlony w strumieniu błędów, a inne wątki nie zostaną dotknięte.

Typowe błędy i antywzorce

  • Wywołanie run() zamiast start()
  • Nieterminowe zakończenie wątku (np. brak obsługi InterruptedException)
  • Uczynienie wątku nieskończonym bez warunków zakończenia

Przykład z życia

Negatywny przypadek

Programista uruchamia wątek metodą run(), myśląc, że działa równolegle z main, ale w rzeczywistości wszystko wykonuje się sekwencyjnie.

Zalety:

  • Logika programu działa poprawnie

Wady:

  • Brak równoległości, pominięta optymalizacja czasu wykonania

Pozytywny przypadek

Prawidłowe użycie start(), poprawna obsługa wyjątków, zastosowanie join() do oczekiwania na zakończenie wątków.

Zalety:

  • Rzeczywista równoległość
  • Zarządzane zakończenie

Wady:

  • Należy dbać o synchronizację, możliwe trudności w debugowaniu