首頁 > 軟體

Java十分鐘入門多執行緒上篇

2022-03-10 13:00:51

什麼是多執行緒?

在學習前,我們先對程式、程序、執行緒、並行、並行有個基礎的概念瞭解:

  • 程式: 為完成指定任務,用程式語言編寫的一組指令的集合,即指一段靜態的程式碼,靜態物件。
  • 程序: 是程式的一次執行過程,是一個動態的過程,程序自身有產生、使用和消亡的過程。(也稱為生命週期,在後面會介紹)
  • 執行緒: 程序可進一步細化為執行緒,是一個程式內部的一條執行路徑,也就是程序內有執行緒
  • 並行: 指兩個或者多個事件在同一時刻發生,(同時發生)
  • 並行: 指兩個或者多個事件在同一個時段內發生,(並不是同時發生)

更好的理解程序和執行緒:

開啟計算機工作管理員:

多執行緒有什麼用?

我們就不看其他長篇大論,簡單的說就是:節省時間,提高效率(在CPU滿足的情況下同時執行多個任務)

舉個例子:

12306大家肯定很熟悉,在高峰期的時候,會有幾十萬的使用者同時在瀏覽和購票,假如你是第1000個進入購票系統的,系統不會讓你等待前面999人買完你才可以買,不管你什麼時候加入購票系統,隨時都可以買,這就是多執行緒。而且CPU的運算速度讓你感覺不用等待延遲(在CPU處理負載能力之內)。

多執行緒優點小結:

  • 提高了使用者的體驗度,使程式的相應速度更快
  • 佔用大量的處理時間的任務可以使用多執行緒來提高CPU的使用效率
  • 可以設優先順序來優化效能

執行緒的生命週期:

執行緒的生命週期包括5個階段: 新建、就緒、執行、阻塞、銷燬

  • 新建:在編譯期間建立執行緒物件就屬於新建狀態,如Thread t1=new Thred()。(在下面介紹如何建立)
  • 就緒: 當一個執行緒物件呼叫了start()方法就屬於就緒狀態,這時候執行緒處於等待CPU執行此執行緒的任務, 誰先搶到cpu資源就誰先執行,是隨機的。
  • 執行: 就緒狀態的執行緒獲得CPU資源執行的任務的時候就是執行狀態,run()方法用於執行執行緒操作
  • 阻塞狀態:在執行狀態的時候,可能因為某些原因導致執行狀態的執行緒變成了阻塞狀態不能再繼續執行任務, 這個時候其他執行緒獲取CPU資源的可能性就更大了,CPU並不會等待阻塞狀態的執行緒(任務)而去執行其他執行緒 的任務,也可以通過執行緒排程的機制「執行緒休眠」讓執行狀態下的執行緒任務變成阻塞,或者讓阻塞狀態的線 程「喚醒」變成就緒狀態。直到再次等待CPU分配資源進入到執行狀態。
  • 銷燬:如果執行緒正常執行完任務後或者執行緒被提前強制終止或者是因為出現異常導致執行緒任務 結束,都屬於銷燬狀態。

關於阻塞狀態的進一步理解:

假如你去超市買東西(建立),選完東西準備結賬(就緒),你在付款了,但是的時候發現錢不夠了(執行),不能完成支付,需要打電話給朋友借一點,因為你沒有辦法支付了(這就進入的阻塞狀態),就不能進入下一步驟(走出超市,對應銷燬)。

注意: 進入阻塞狀態後並不是說不管你了,而是準備好後再次讓CPU來處理你。就是你借到錢了,收銀員會再次讓你去付款。

建立多執行緒:

主執行緒:

當Java程式啟動的時候,一個執行緒立刻執行,該執行緒叫做主執行緒(main Thread),因為他是程式開始就執行的。

主執行緒的作用:

  • 產生其他子執行緒的執行緒
  • 必須完成最後的執行,因為它還需要執行各種關閉動作

實現多執行緒有5種方式:

  • 繼承Thread父類別重寫run()方法,Java是單繼承如果繼承了Thread其他父類別就不能再繼承。(這種方式不建議)
  • 實現Runable介面重寫run()方法。(最常用)
  • 實現Callable介面,呼叫有返回值的call方法
  • 執行緒池建立多執行緒
  • 通過Java8新特性Lambda表示式實現多執行緒

主執行緒:

public class test {
    public static void main(String[] args) {
        //獲取當前執行緒的物件
        Thread t = Thread.currentThread();
        //輸出當前執行緒的名字:
        System.out.println(t.getName());
        t.setName("我是主執行緒");
        System.out.println(t.getName());
    }
}

//輸出:
//main
//我是主執行緒

通過上面的程式碼可以知道當前主執行緒的名字,也可以修改執行緒名、 關於Thread的方法介紹參考官方檔案:

https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Thread.html

1、繼承Thread父類別重寫run()方法建立多執行緒:

繼承Thread重寫run方法:

//建立一個以main為主執行緒的子執行緒
public class MyThread extends Thread{
    @Override
    public void run(){
        for (int i = 1; i < 6; i++) {
            System.out.println("我是子執行緒:"+i);
        }
    }
}

測試類:

public class test {
    public static void main(String[] args) {
        
        //建立子執行緒物件(新建狀態)
        MyThread t = new MyThread();
        //就緒狀態,等待CPU執行該執行緒任務
        t.start();
        for (int i = 1; i < 6; i++) {
            System.out.println("main任務:主執行緒執行:"+i);
        }
    }
}

結果:

2、實現Runable介面重寫run()方法(最常用)

建立子執行緒:

public class MyThread implements Runnable{

    @Override
    public void run(){
        for (int i = 1; i < 10; i++) {
            System.out.println("子執行緒-"+Thread.currentThread().getName()+i);
        }
    }
}

測試類:

public class test {
    public static void main(String[] args) {

        //建立子執行緒物件(新建狀態)
        MyThread t1 = new MyThread();
        t1.setName("我是A執行緒:");
        MyThread t2 = new MyThread();
        t2.setName("我是B執行緒:");
        MyThread t3 = new MyThread();
        t3.setName("我是C執行緒:");

        //就緒狀態,等待CPU執行該執行緒任務
        t1.start();
        t2.start();
        t3.start();
    }
}

結果:

3、實現Callable<?>介面實現有返回值的多執行緒

public class MyThread implements Callable<Boolean> {

    @Override
    public Boolean call() throws Exception {
        try{
            //因為是泛型介面,call實 現了執行緒任務,並且返回值可以自定義
            System.out.println("實現了Callable介面重寫call方法");
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }
}

測試類:

public class test {
    public static void main(String[] args) throws ExecutionException, InterruptedException {

        //建立物件:
        MyThread myThread = new MyThread();
        //通過執行緒池幫你建立了2個執行緒物件
        //ExecutorService是Java中對執行緒池定義的一個介面,它java.util.concurrent包中
        ExecutorService service = Executors.newFixedThreadPool(2);
        //通過執行緒池物件呼叫submit方法,提交執行call方法的執行緒任務,最後返回結果
        Future<Boolean> result1 = service.submit(myThread);
        Future<Boolean> result2 = service.submit(myThread);

        boolean r1= result1.get();
        boolean r2= result2.get();

輸出:

實現了Callable介面重寫call方法
實現了Callable介面重寫call方法
我是子執行緒1,返回的結果:true
我是子執行緒2,返回的結果:true

其他兩個建立多執行緒的方式不怎麼用,就不一一介紹,大家也可以看看其他技術部落格學習~~

小結:

這篇文章主要將了多執行緒的概念以及建立多執行緒的方式,多執行緒還有很多的內容,就在下一篇再繼續介紹啦!感謝閱讀!

到此這篇關於Java十分鐘入門多執行緒上篇的文章就介紹到這了,更多相關Java 多執行緒內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com