JavaRush /Java Blog /Random-TW /多線程:線程類別方法的作用

多線程:線程類別方法的作用

在 Random-TW 群組發布
你好!今天我們繼續聊多線。讓我們來看看 Thread 類別以及它的幾個方法是如何運作的。以前,當我們研究類別方法時,我們通常會簡單地這樣寫:「方法的名稱」->「它的作用」。
多執行緒:Thread 類別的方法的作用 - 1
這不適用於 Thread 方法:) 它們的邏輯比較複雜,沒有幾個例子是不可能理解的。

Thread.start() 方法

讓我們從重複開始。Thread您可能還記得,您可以透過從類別繼承您的類別並重寫其中的方法來建立線程run()。但是,當然,它不會自行開始。為此,我們呼叫物件上的方法start()多執行緒:Thread 類別的方法的作用 - 2讓我們記住上一講的例子:
public class MyFirstThread extends Thread {

   @Override
   public void run() {
       System.out.println("Выполнен поток " + getName());
   }
}


public class Main {

   public static void main(String[] args) {

       for (int i = 0; i < 10; i++) {
           MyFirstThread thread = new MyFirstThread();
           thread.start();
       }
   }
}
請注意:要啟動線程,您必須呼叫特殊方法start(),而不是run()! 這是一個很容易犯的錯誤,尤其是在第一次學習多執行緒時。如果在我們的範例中呼叫物件的方法run()而不是start(),結果將如下所示:
public class Main {

   public static void main(String[] args) {

       for (int i = 0; i < 10; i++) {
           MyFirstThread thread = new MyFirstThread();
           thread.run();
       }
   }
}
執行緒 0 執行緒執行 執行緒 1 執行緒執行 執行緒 2 執行緒執行 執行緒 8 執行緒執行 執行緒 9 執行緒執行查看輸出順序:一切都嚴格按順序 進行。奇怪吧?我們對此並不習慣,因為我們已經知道執行緒啟動和執行的順序是由作業系統內部的超級智慧——執行緒調度程式決定的。也許我只是幸運?當然,這不是運氣問題。您可以透過多運行該程式幾次來驗證這一點。重點是直接呼叫方法和run()多執行緒無關。在這種情況下,程式將在主執行緒中執行——即執行該方法的執行緒main()。它只會依序輸出 10 行,僅此而已。不會啟動 10 個執行緒。因此,為了以後記住,不斷地檢視自己。如果您希望它完成run(),請呼叫它start()。讓我們繼續。

Thread.sleep() 方法

若要暫停目前執行緒的執行一段時間,請使用sleep(). 多執行緒:Thread 類別的方法的作用 - 3此方法sleep()將毫秒數作為參數,即執行緒需要進入睡眠狀態的時間。
public class Main {

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

       long start = System.currentTimeMillis();

       Thread.sleep(3000);

       System.out.println(" - Сколько я проспал? \n - " + ((System.currentTimeMillis()-start)) / 1000 + " секунды");

   }
}
控制台輸出: - 我睡了多久?- 3 秒 請注意:該方法sleep()是靜態的:它將當前執行緒置於睡眠狀態。也就是說,目前正在工作的那個。另一個重要的細微差別:睡眠狀態下的流程可以中斷。這樣的話,程式就會出現異常InterruptedException。我們將看下面的一個例子。順便問一下,線程“醒來”後會發生什麼?它會立即從中斷處繼續執行嗎?不。執行緒喚醒後(當作為參數傳遞的時間到期時Thread.sleep()),它進入可運行狀態。然而,這並不意味著線程調度程序將運行它。它很可能會優先考慮其他一些“非睡眠”線程,而我們的“新喚醒”線程稍後會繼續工作。一定要記住:“醒來並不意味著那一刻繼續工作!”

Thread.join() 方法

Многопоточность: что делают методы класса Thread - 4該方法join()暫停當前執行緒的執行,直到另一個執行緒完成。如果我們有 2 個線程,t1並且t2,並且我們寫 -
t1.join()
t2在 t1 完成其工作之前不會開始工作。此方法join()可以用來保證執行緒的執行順序。讓我們join()用一個例子來看看這項工作:
public class ThreadExample extends Thread {

   @Override
   public void run() {

       System.out.println("Начало работы потока " + getName());

       try {
           Thread.sleep(5000);
       } catch (InterruptedException e) {
           e.printStackTrace();
       }
       System.out.println("Поток " + getName() +  " завершил работу.");
   }
}


public class Main {

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

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

       t1.start();


 /*Второй поток t2 начнет выполнение только после того, How будет завершен
       (or бросит исключение) первый поток - t1*/
       try {
           t1.join();
       } catch (InterruptedException e) {
           e.printStackTrace();
       }

       t2.start();

       //Главный поток продолжит работу только после того, How t1 и t2 завершат работу
       try {
           t1.join();
           t2.join();
       } catch (InterruptedException e) {
           e.printStackTrace();
       }

       System.out.println("Все потоки закончor работу, программа завершена");

   }
}
我們創建了一個簡單的類別ThreadExample。它的任務是在螢幕上顯示一條關於工作開始的訊息,然後休眠 5 秒鐘,最後通知工作完成。沒什麼複雜的。主要邏輯包含在類別中Main。看評論:利用該方法,join()我們成功控制了執行緒的執行順序。如果您還記得主題的開頭,線程調度程序就是這樣做的。他自行決定推出它們:每次都不同。在這裡,使用該方法,我們確保首先啟動並執行線程t1,然後是線程t2,只有在它們之後才是程式執行的主線程。前進。在實際程式中,經常會遇到需要中斷某個執行緒執行的情況。例如,我們的執行緒正在運行,但它正在等待某個事件或條件得到滿足。如果發生這種情況,它就會停止。如果有類似的方法,這可能是合乎邏輯的stop()。然而,一切並沒有那麼簡單。曾幾何時,Thread.stop()Java 中確實存在一種方法,它允許您中斷執行緒的工作。但後來它被從 Java 庫中刪除了。您可以在 Oracle 文件中尋找它,並看到它被標記為deprecated。為什麼?因為它只是停止了流動,沒有任何額外的工作。例如,線程可以處理資料並更改其中的某些內容。stop()然後他在工作中突然被打倒了——就是這樣。沒有正確的關閉,沒有釋放資源,甚至沒有錯誤處理——這一切都沒有發生。誇張地說,這個方法stop()簡直摧毀了它所經過的一切。其操作可以與某人從插座上拔下插頭來關閉電腦進行比較。是的,您可以達到預期的結果。但每個人都明白,幾週後電腦將不會為此說「謝謝」。為此,Java中中斷執行緒的邏輯發生了變化,現在使用了一種特殊的方法— interrupt().

Thread.interrupt() 方法

如果呼叫執行緒上的方法 interrupt()會發生什麼?有 2 個選項:
  1. 如果該物件當時處於等待狀態,例如joinsleep,則等待將中斷,程式將會被拋出InterruptedException
  2. 如果此時執行緒處於工作狀態,則該物件的布林標誌將會被設定interrupted
但是我們必須檢查物件的該標誌的值並自己正確地完成工作!為此,該類別Thread有一個特殊的方法 - boolean isInterrupted(). 讓我們回到主課講座中的時鐘範例。為了方便起見,稍微簡化一下:
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("Работа потока была прервана");
               break;
           }
           System.out.println("Tik");
       }
   }
}
在我們的例子中,時鐘每秒開始計時。在第 10 秒我們中斷時脈流。如您所知,如果我們嘗試中斷的線程處於等待狀態之一,則會導致InterruptedException. 這種類型的異常是受檢查的異常,因此可以輕鬆捕獲它並執行我們的程式終止邏輯。這就是我們所做的。 Here is our result: Tik Tik Tik Tik Tik Tik Tik Tik Tik The thread's work was interrupted. This concludes our introduction to the main methods of the class Thread. 為了鞏固您的知識,您可以觀看有關多線程的視訊講座:
它將作為極好的附加材料!最後,在概述了這些方法之後,它準確地告訴了我們接下來將在課程中學習的內容:) 祝你好運!
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION