多線程:基礎、Thread類、用法
尚硅谷JavaSE筆記-18

多線程

名詞解釋

英文 台灣 中國 意義
Program 程式 程序 靜態的程式碼集合
Process 程序(進程) 進程 動態、被執行中且載入記憶體的program,也是 OS 分配資源的最小單位。打開工作管理員看到的就是這個
Thread 執行緒 線程 一個進程裡至少會有一個線程,表示內部的一條執行路徑。把進程比喻為一個工廠,線程則是工廠裡面的工人,負責任務的實際執行。同一個Process內的Thread使用相同的Memory Space,但這些Thread各自擁有其Stack。換句話說,Thread能透過reference存取到相同的Object,但是local variable卻是各自獨立的。白話:共享方法區跟堆,獨立棧跟計數器
Coroutine 協程 協程 輕量級的執行緒,由使用者掌控,例如GO的goroutine
Concurrent 並行 並發 一個 CPU 會去做多件事,但是同一個時間點之內只會做一件事,像是早上做 Job1、下午做 Job2、晚上做 Job3不斷的切換,目標是希望能做更多的事
Parallel 平行 並行 多個 CPU 在同一個時間點內會去做多件事,例如會有三個人同時分別在做 Job1、Job2、Job3 的事情。目標是希望能把事情更快速的做完。

需求來源

  • 希望同時執行複數的任務,例如一邊執行main方法,GC一邊收垃圾
  • 需要等待的狀況,例如等用戶輸入、等IO、等網路連接

Java多線程-方法一

  1. 造一個類,繼承Thread

  2. 重寫此類的run方法(將想多線程執行的代碼包進去)

  3. 實例化此類的一個物件

  4. 透過此物件調用start();,此時啟動此線程並且調用他的run()方法

  5. 若想再啟動另一條線程,需要再new一個物件,同一物件start多次會報IllegalThreadStateException

  6. 舉例:

    public class MyThread extends Thread {
        @Override
        public void run() {
            for (int i = 0; i < 10000; i++) {
                if (i % 2 == 0) {
                    System.out.println(i + "新造#####");
                }
            }
        }
    }
    
    class Test {
        public static void main(String[] args) {
            for (int i = 0; i < 10000; i++) {
                if (i % 2 == 0) {
                    System.out.println(i + "主線程*****");
                }
            }
            MyThread t1 = new MyThread();
            t1.start();
    
            new Thread() {
                @Override
                public void run() {
                    for (int i = 0; i < 10000; i++) {
                        if (i % 2 != 0) {
                            System.out.println(i + "匿名類?????");
                        }
                    }
                }
            }.start();
    
        }
    }
    
  7. 也可以透過匿名類的方法new Thread(){//要執行的代碼}.start();

Thread類的常用方法

  • start():啟動當前線程、調用其run()
  • currentThread():靜態方法,返回當前執行代碼的線程
  • getName():獲取當前線程的名字,常與"currentThread().getName()“這樣連用
  • setName(String):設定線程名,在start前後都有用,也可以用Thread.currentThread().setName("設定主線程名");
  • yeild():靜態方法,釋放當前線程的執行權(但也有可能馬上又搶回),會拋異常
  • join():在線程A中調用線程B的join(),此時A就阻塞,等B完全做完才繼續A。白話:在我的地盤說誰.join就是我讓誰插隊
  • sleep(毫秒):當前線程休息,休息時是阻塞的,會拋異常
  • isAlive():判斷當前線程是否存活
  • setDaemon(true):轉為守護線程

線程的優先級

  • 寫在Thread中的,最小是1,預設是5,最大是10
public final static int MIN_PRIORITY = 1;
public final static int NORM_PRIORITY = 5;
public final static int MAX_PRIORITY = 10;
  • getPriority():獲取優先級
  • setPriority(int):設置優先級
  • 但並不是說高優先就一定先執行完,只是機率上的

Java多線程-方法二

  1. 造一個實現Runnable接口的類

  2. 實現其中的抽象方法run()

  3. 創建實現類的實例物件

  4. 將此物件作為參數,傳到Thread類的構造器中,創建Thread類的物件

  5. 通過此Thread類的物件調用start()

  6. 自訂的類是作為形參,想再創一個線程只要new Thread即可,舉例:

    class MyThread2 implements Runnable {
        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                System.out.println(Thread.currentThread().getName() + "-" + i);
            }
        }
    }
    
    class test {
        public static void main(String[] args) {
            MyThread2 m2 = new MyThread2();
            Thread t1 = new Thread(m2);
            t1.start();
            Thread t2 = new Thread(m2);
            t2.start();
        }
    }
    
  7. 優勢在於只造了一個類,假如類中有個屬性需要被共用,不管後面造了多少線程都是共用這個變量(而不需使用static宣告)

  8. 還一個優勢在於,本身類可能已經有繼承對象了,而我只要實現接口就可以

  9. 其實方法一點開源碼看也是方法二,實際就優先用方法二吧

小結

  • 多線程的核心就是重寫run()、調用start()方法

上次修改於 2021-12-03