CodeGym /Blog Java /Random-PL /Wielowątkowość: Do czego służą metody klasy Thread
Autor
Pavlo Plynko
Java Developer at CodeGym

Wielowątkowość: Do czego służą metody klasy Thread

Opublikowano w grupie Random-PL
Cześć! Dzisiaj będziemy nadal mówić o wielowątkowości. Przyjrzyjmy się klasie Thread i działaniu kilku jej metod. Kiedy wcześniej studiowaliśmy metody klasowe, zwykle pisaliśmy po prostu tak: <nazwa metody> -> <co robi metoda>. Wielowątkowość: Do czego służą metody klasy Thread - 1To nie zadziała z Threadmetodami '' :) Mają bardziej złożoną logikę, której nie będziesz w stanie zrozumieć bez kilku przykładów.

Metoda Thread.start().

Zacznijmy od powtórzenia się. Jak zapewne pamiętasz, możesz utworzyć wątek, sprawiając, że twoja klasa dziedziczy klasę Threadi nadpisuje run()metodę. Ale oczywiście sam się nie uruchomi. W tym celu wywołujemy start()metodę naszego obiektu. Wielowątkowość: Do czego służą metody klasy Thread - 2Przypomnijmy przykład z poprzedniej lekcji:

public class MyFirstThread extends Thread {

   @Override
   public void run() {
       System.out.println("Thread executed: " + getName());
   }
}


public class Main {

   public static void main(String[] args) {

       for (int i = 0; i < 10; i++) {
           MyFirstThread thread = new MyFirstThread();
           thread.start();
       }
   }
}
Uwaga: Aby rozpocząć wątek, musisz wywołaćstart()metodę specjalną, a nierun()metodę! Jest to błąd, który łatwo popełnić, zwłaszcza gdy po raz pierwszy zaczynasz uczyć się wielowątkowości. W naszym przykładzie, jeśli wywołaszrun()metodę 10 razy zamiaststart(), otrzymasz to:

public class Main {

   public static void main(String[] args) {

       for (int i = 0; i < 10; i++) {
           MyFirstThread thread = new MyFirstThread();
           thread.run();
       }
   }
}
Spójrz na wyniki naszego programu: Wątek wykonany: Wątek-0 Wątek wykonany: Wątek-1 Wątek wykonany: Wątek-2 Wątek wykonany: Wątek-3 Wątek wykonany: Wątek-4 Wątek wykonany: Wątek-5 Wątek wykonany: Wątek-6 Wątek wykonany: Wątek-7 Wątek wykonany: Wątek-8 Wątek wykonany: Wątek-9 Spójrz na kolejność wyjścia: Wszystko dzieje się w idealnej kolejności. Dziwne, co? Nie jesteśmy do tego przyzwyczajeni, ponieważ wiemy już, że kolejność uruchamiania i wykonywania wątków jest określana przez nadrzędny intelekt w naszym systemie operacyjnym: harmonogram wątków. Może po prostu mieliśmy szczęście? Oczywiście nie chodzi tu o szczęście. Możesz to sprawdzić, uruchamiając program jeszcze kilka razy. Problem polega na tym, że wywołanierun()metoda bezpośrednio nie ma nic wspólnego z wielowątkowością. W takim przypadku program zostanie wykonany w głównym wątku, tym samym wątku, który wykonuje metodę main(). Po prostu kolejno wypisuje 10 linii na konsoli i to wszystko. 10 wątków nie zostało rozpoczętych. Pamiętaj więc o tym na przyszłość i stale się sprawdzaj. Jeśli chcesz, aby run()metoda została wywołana, wywołaj start(). Idźmy dalej.

Metoda Thread.sleep().

Aby na chwilę zawiesić wykonywanie bieżącego wątku, używamy sleep()metody. Wielowątkowość: Do czego służą metody klasy Thread - 3Metoda sleep()przyjmuje jako argument liczbę milisekund, która wskazuje czas uśpienia wątku.

public class Main {

   public static void main(String[] args) throws InterruptedException {

       long start = System.currentTimeMillis();

       Thread.sleep(3000);

       System.out.println(" - How long did I sleep? \n - " + ((System.currentTimeMillis()-start)) / 1000 + " seconds");

   }
}
Wyjście konsoli: - Jak długo spałem? - 3 sekundy Uwaga: metoda sleep()jest statyczna: uśpi bieżący wątek. To znaczy ten, który jest obecnie wykonywany. Oto kolejna ważna kwestia: uśpiona nić może zostać przerwana. W takim przypadku program wyrzuca plik InterruptedException. Rozważymy przykład poniżej. A propos, co się dzieje po przebudzeniu wątku? Czy nadal będzie wykonywany od miejsca, w którym został przerwany? Nie. Po przebudzeniu wątku, tj. czasie, który Thread.sleep()minął jako argument do, przechodzi on do stanu wykonalnegopaństwo. Ale to nie znaczy, że program do planowania wątków go uruchomi. Całkiem możliwe, że da pierwszeństwo jakiemuś nieuśpionemu wątkowi i pozwoli naszemu świeżo obudzonemu wątkowi kontynuować pracę nieco później. Pamiętaj o tym: przebudzenie nie oznacza natychmiastowego kontynuowania pracy!

Metoda Thread.join().

Wielowątkowość: Do czego służą metody klasy Thread - 4Metoda join()wstrzymuje wykonywanie bieżącego wątku do czasu zakończenia innego wątku. Jeśli mamy 2 wątki t1i t2, i piszemy

t1.join()
następnie t2nie rozpocznie się, dopóki nie t1zakończy swojej pracy. Metodę join()można wykorzystać do zagwarantowania kolejności wykonywania wątków. Rozważmy, jak join()działa metoda w następującym przykładzie:

public class ThreadExample extends Thread {

   @Override
   public void run() {

       System.out.println("Thread started: " + getName());

       try {
           Thread.sleep(5000);
       } catch (InterruptedException e) {
           e.printStackTrace();
       }
       System.out.println("Thread " + getName() + " is finished.");
   }
}


public class Main {

   public static void main(String[] args) throws InterruptedException {

       ThreadExample t1 = new ThreadExample();
       ThreadExample t2 = new ThreadExample();

       t1.start();


 /* The second thread (t2) will start running only after the first thread (t1)
       is finished (or an exception is thrown) */
       try {
           t1.join();
       } catch (InterruptedException e) {
           e.printStackTrace();
       }

       t2.start();

       // The main thread will continue running only after t1 and t2 have finished
       try {
           t1.join();
           t2.join();
       } catch (InterruptedException e) {
           e.printStackTrace();
       }

       System.out.println("All threads have finished. The program is finished.");

   }
}
Stworzyliśmy prostą ThreadExampleklasę. Jego zadaniem jest wyświetlenie komunikatu, że wątek został uruchomiony, zasypianie na 5 sekund, a na koniec zgłoszenie, że praca została zakończona. Bułka z masłem. Główna logika jest w Mainklasie. Spójrz na komentarze: używamy tej join()metody do skutecznego zarządzania kolejnością wykonywania wątków. Jeśli pamiętasz, jak rozpoczęliśmy ten temat, kolejność wykonywania jest obsługiwana przez program do planowania wątków. Prowadzi wątki według własnego uznania: za każdym razem w inny sposób. Tutaj używamy metody, aby zagwarantować, że t1wątek zostanie najpierw uruchomiony i wykonany jako pierwszy, a następniet2wątek i dopiero potem główny wątek programu będzie kontynuowany. Iść dalej. W rzeczywistych programach często znajdziesz sytuacje, w których będziesz musiał przerwać wykonywanie wątku. Na przykład nasz wątek działa, ale oczekuje na określone zdarzenie lub warunek. Jeśli tak się stanie, wątek zatrzymuje się. Pewnie miałoby to sens, gdyby istniała jakaś stop()metoda. Ale to nie takie proste. Dawno, dawno temu Java rzeczywiście miała Thread.stop()metodę i pozwalała na przerwanie wątku. Ale później został usunięty z biblioteki Java. Możesz go znaleźć w dokumentacji Oracle i zobaczyć, że jest oznaczony jako przestarzały. Dlaczego? Ponieważ po prostu zatrzymał wątek, nie robiąc nic więcej. Na przykład wątek może pracować z danymi i coś zmieniać. Następnie w połowie swojej pracy został nagle i bezceremonialnie odcięty metodą stop(). Bez odpowiedniego wyłączenia, zwolnienia zasobów, nawet obsługi błędów — nic z tego nie mogło się wydarzyć. Lekko przesadzając, stop()metoda po prostu niszczyła wszystko na swojej drodze. To było jak wyciągnięcie przewodu zasilającego z gniazdka w celu wyłączenia komputera. Tak, możesz uzyskać pożądany rezultat. Ale wszyscy wiedzą, że po kilku tygodniach komputer nie będzie ci dziękował za takie traktowanie. Dlatego logika przerywania wątków zmieniła się w Javie i teraz używa specjalnej interrupt()metody.

Metoda Thread.interrupt().

Co się stanie, jeśli interrupt()metoda zostanie wywołana w wątku? Istnieją 2 możliwości:
  1. Jeśli obiekt był w stanie oczekiwania, na przykład z powodu metod joinlub sleep, to oczekiwanie zostanie przerwane i program zgłosi błąd InterruptedException.
  2. Jeśli wątek był w stanie funkcjonalnym, wówczas interruptedna obiekcie zostanie ustawiona flaga logiczna.
Musimy jednak sprawdzić wartość tej flagi na obiekcie i poprawnie wykonać pracę we własnym zakresie! Dlatego Threadklasa ma boolean isInterrupted()metodę. Wróćmy do przykładu z zegarem, który był na lekcji w kursie podstawowym. Dla wygody nieco go uprościliśmy:

public class Clock extends Thread {

   public static void main(String[] args) throws InterruptedException {
       Clock clock = new Clock();
       clock.start();

       Thread.sleep(10000);
       clock.interrupt();
   }

   public void run() {
       Thread current = Thread.currentThread();

       while (!current.isInterrupted())
       {
           try {
               Thread.sleep(1000);
           } catch (InterruptedException e) {
               System.out.println("The thread was interrupted");
               break;
           }
           System.out.println("Tick");
       }
   }
}
W takim przypadku zegar jest uruchamiany i zaczyna tykać co sekundę. W 10. sekundzie przerywamy wątek zegara. Jak już wiesz, jeśli wątek, który próbujemy przerwać, znajduje się w jednym ze stanów oczekiwania, wynikiem jest plik InterruptedException. Jest to sprawdzony wyjątek, więc możemy go łatwo złapać i wykonać naszą logikę, aby zakończyć program. I to właśnie zrobiliśmy. Oto nasz wynik: Tick Tick Tick Tcik Tick Tick Tick Tick Tick Wątek został przerwany Na tym kończy się nasze wprowadzenie do Threadnajważniejszych metod klasy. Powodzenia!
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION