1. 程式人生 > 實用技巧 >java 多執行緒-1

java 多執行緒-1

一、程式、程序、執行緒簡介

  1. 程式(program)是為完成特定任務、用某種語言編寫的一組指令的集合。即指一段靜態的程式碼,靜態物件

  2. 程序(process)是程式的一次執行過程,或是正在執行的一個程式。是一個動態的過程:有它自身的產生、存在和消亡的過程。——生命週期

    • 如:執行中的QQ,執行中的MP3播放器
    • 程式是靜態的,程序是動態的
    • 程序作為資源分配的單位,系統在執行時會為每個程序分配不同的記憶體區域
  3. 執行緒(thread),程序可進一步細化為執行緒,是一個程式內部的一條執行路徑。

    • 若一個程序同一時間並行執行多個執行緒,就是支援多執行緒的

    • 執行緒作為排程和執行的單位每個執行緒擁有獨立的執行棧

      程式計數器(pc)執行緒切換的開銷小

      1. 棧和程式計數器,每個執行緒各自有一套
      2. 方法區、堆一個程序一份,一個程序裡面有個多個執行緒,這也就意味這,多個執行緒共享方法區和堆。

  • 一個程序中的多個執行緒共享相同的記憶體單元/記憶體地址空間它們從同一堆中分配物件,可以訪問相同的變數和物件。這就使得執行緒間通訊更簡便、高效。但多個執行緒操作共享的系統資源可能就會帶來安全的隱患。

二、並行與併發

並行:多個CPU同時執行多個任務。比如:多個人同時做不同的事。

併發:一個CPU(採用時間片)同時執行多個任務。比如:秒殺、多個人做同一件事。

三、執行緒的建立方式一 【繼承Thread類】

  1. Thread類的特性。

    • 每個執行緒都是通過某個特定Thread物件的run()方法來完成操作的,經常把run()方法的主體稱為執行緒體。
    • 通過該Thread物件的start()方法來啟動這個執行緒,而非直接呼叫run()。【直接調動run方法不是多執行緒】
  2. Thread類構造器

    • Thread():建立新的Thread物件
    • Thread(String threadname):建立執行緒並指定執行緒例項名
    • Thread(Runnable target):指定建立執行緒的目標物件,它實現了Runnable介面中的run方法
    • Thread(Runnable target, String name):建立新的Thread物件
  1. 繼承Thread類的實現步驟

    (1)定義子類繼承Thread類。

    (2)子類中重寫Thread類中的run方法。

    (3)建立Thread子類物件,即建立了執行緒物件。

    (4)呼叫執行緒物件start方法:啟動執行緒,呼叫run方法。

    public class ThreadTest {
        public static void main(String[] args) {
            MyThread myThread = new MyThread();
            myThread.start(); // 啟動執行緒
            for (int i = 0; i < 300; i++) {
                if (i % 2 != 0) {
                    System.out.println("main:"+i);
                }
            }
        }
    }
    
    class MyThread extends Thread {
        @Override
        public void run() { // 重寫run方法
            for (int i = 1; i < 101; i++) {
                if (i % 2 == 0) {   
                    System.out.println(i+" ");
                }
            }
        }
    
    }
    
  2. Thread類的有關方法

    • void start():啟動執行緒,並執行物件的run()方法 run():執行緒在被排程時執行的操作
    • String getName():返回執行緒的名稱
    • void setName(String name):設定該執行緒名稱
    • static Thread currentThread():返回當前執行緒。在Thread子類中就是this,通常用於主執行緒和Runnable實現類
    • static void yield():執行緒讓步
      • 暫停當前正在執行的執行緒,把執行機會讓給優先順序相同或更高的執行緒
      • 若佇列中沒有同優先順序的執行緒,忽略此方法
    • join():當某個程式執行流中呼叫其他執行緒的join()方法時,呼叫執行緒將被阻塞,直到join()方法加入的join執行緒執行完為止
      • 低優先順序的執行緒也可以獲得執行
    • static void sleep(longmillis):(指定時間:毫秒)
      • 令當前活動執行緒在指定時間段內放棄對CPU控制,使其他執行緒有機會被執行,時間到後重排隊
      • 丟擲InterruptedException異常
    • stop():強制執行緒生命期結束,不推薦使用
    • booleanisAlive():返回boolean,判斷執行緒是否還活著

四、執行緒的排程

  1. cpu的排程策略:
  • 時間片

  • 搶佔式:高優先順序的執行緒搶佔CPU

  1. Java的排程方法:
  • 同優先順序執行緒組成先進先出佇列(先到先服務),使用時間片策略
  • 對高優先順序,使用優先排程的搶佔式策略
  1. 執行緒的優先順序

    • MAX_PRIORITY:10

    • MIN_PRIORITY:1

    • NORM_PRIORITY:5

    涉及的方法:

    • getPriority():返回執行緒優先值
    • setPriority(intnewPriority):改變執行緒的優先順序

    說明:

    • 執行緒建立時繼承父執行緒的優先順序
    • 低優先順序只是獲得排程的概率低,並非一定是在高優先順序執行緒之後才被呼叫

五、執行緒的建立方式二 【方式二:實現Runnable介面】

  1. 定義子類,實現Runnable介面。
  2. 類中重寫Runnable介面中的run方法。
  3. 通過Thread類含參構造器建立執行緒物件。
  4. 將Runnable介面的子類物件作為實際引數傳遞給Thread類的構造器中。
  5. 呼叫Thread類的start方法:開啟執行緒,呼叫Runnable子類介面的run方法。
public class RunnableTest {
    public static void main(String[] args) {
        RunTest runTest = new RunTest(); // new 一個例項物件
        Thread thread = new Thread(runTest); // 把例項物件傳入Thread的構造器中。
        thread.start(); // 開啟執行緒
    }
}

class RunTest implements Runnable{ // 實現Runnable介面
    @Override
    public void run() {
        for (int i = 0; i < 101; i++) {
            if (i % 2 == 0) {
                System.out.println(i);
            }
        }
    }
}

六、比較建立執行緒的兩種方式

  1. 開發中:優先選擇——實現Runnable介面的方式

  2. 原因:

    • 實現的方式沒有類的單繼承性的侷限性
    • 實現的方式更適合來處理多個執行緒有共享資料的情況
      • 因為多個執行緒使用的是同一個物件。
      • 即不用加static關鍵字,即可處理資料共享。
  3. 聯絡:

    • Thread 類也實現了Runnable介面
    • 兩中方式都需要重寫run(),將執行緒的要執行的邏輯宣告在run()中