Java 多線程(一):多線程基礎詳解

多線程概述

  • 多線程是指一個進程(執(zhí)行中的程序)同時運行多個線程(進程中負責程序執(zhí)行的執(zhí)行單元),多線程可以協(xié)作完成進程工作,其目的是更好的利用 CPU 資源

并發(fā)與并行

  • 并行:多核多 CPU 或多機器處理同一段處理邏輯的時候,同一時刻多個執(zhí)行流共同執(zhí)行
  • 并發(fā):是指通過 CPU 的調(diào)度算法,使用戶感覺像是再同時處理多個任務,但同一時刻只有一個執(zhí)行流占用 CPU 執(zhí)行,即使多核多 CPU 的環(huán)境下還是會使用并發(fā),以提高處理效率,主要的調(diào)度算法有:
    • 分時調(diào)度:每個線程輪流獲取 CPU 使用權,各個線程平均 CPU 時間片
    • 搶占式調(diào)度:Java 虛擬機使用該調(diào)度模型,它會根據(jù)線程優(yōu)先級,先調(diào)度優(yōu)先級高的線程,若線程優(yōu)先級相同則隨機選取線程執(zhí)行

線程終止的四種方式

  • run() 方法執(zhí)行結束后自然終止
  • 使用 stop() 方法終止
  • 使用 volatile 標志位(外部控制的自然死亡)
  • 使用 interrupt() 方法中斷運行狀態(tài)和阻塞狀態(tài)線程,interrupt() 方法會改變中斷狀態(tài),但如果不是在阻塞狀態(tài)則不會拋出異常,通過 isInterrupt 來作為中斷標志推出循環(huán)
  • 注意:當線程拋出一個未被捕獲的異?;蝈e誤時,線程會異常終止

守護線程

  • 守護線程也稱為后臺線程,在通過 start() 方法調(diào)用前先調(diào)用 setDeamon(true) 將線程設置為守護線程
  • 守護線程會在所有前臺線程死亡后由 JVM 通知死亡
  • 守護線程最大的應用就是垃圾回收線程,它是一個典型的守護線程

線程狀態(tài)

線程狀態(tài)
  • 新建狀態(tài):創(chuàng)建了線程 Thread 對象就進入了新建狀態(tài)
  • 就緒狀態(tài):調(diào)用 start() 方法就會為線程分配私有的方法棧,程序計算器資源,如果得到 CPU 資源就會從就緒狀態(tài)轉為運行狀態(tài)
  • 運行狀態(tài):就緒狀態(tài)得到 CPU 資源就會轉為運行狀態(tài),執(zhí)行 run() 方法,當調(diào)用 yield() 時線程會讓步,從運行狀態(tài)轉到就緒狀態(tài),但該過程可能是及其短暫的,如果當前線程擁有較高優(yōu)先級,即使讓步后還是會進入運行狀態(tài)
  • 阻塞狀態(tài):會導致阻塞狀態(tài)的方法主要有:sleep()、wait()、join()、等待獲取鎖、等待 I/O 等情況,在這些情況被處理后就會轉為就緒狀態(tài),等待調(diào)度
  • 終止狀態(tài):上述所說的四種線程終止

基本線程類 Thread 與 Runnable 接口、Callable 接口

Thread

  • 繼承 Thread 并重寫其 run() 方法,通過線程對象的 start() 方法來啟動線程
public class Test {
    public static void main(String[] args)  {
        MyThread thread = new MyThread();
        thread.start();
    }
}
class MyThread extends Thread{
    private static int num = 0;
    public MyThread(){
        num++;
    }
    @Override
    public void run() {
        System.out.println("主動創(chuàng)建的第"+num+"個線程");
    }
}
  • 方法描述
    • sleep():等待一段時間,但是不釋放鎖,時間到后進入就緒狀態(tài)等待調(diào)度
    • wait():讓線程進入等待狀態(tài),同時釋放當前線程所持有的鎖,直到其它線程調(diào)用此對象 notify() 或 notifyAll() 方法后,當前線程會被喚醒,進入就緒狀態(tài),等待調(diào)度(注意:wait 方法只能在 synchronized 方法里使用)
    • join():把指定的線程加入到當前線程,可以將兩個交替執(zhí)行的線程合并為順序執(zhí)行的線程,比如在線程 B 中調(diào)用了線程 A 的 join() 方法,直到線程 A 執(zhí)行完畢后才會繼續(xù)執(zhí)行線程 B
    • notify() 與 notifyAll():notify 只會通知一個在等待的對象,而 nofityAll() 會通知所有再等待的對象

Runnable

  • 實現(xiàn) Runnable 接口需重寫 run 方法
  • Runnable 是"任務",通過實現(xiàn)該接口,定義一個任務,然后將子任務交由 Thread 去執(zhí)行
public class Test {
    public static void main(String[] args)  {
        System.out.println("主線程ID:"+Thread.currentThread().getId());
        MyRunnable runnable = new MyRunnable();
        Thread thread = new Thread(runnable);
        thread.start();
    }
} 
class MyRunnable implements Runnable{
    public MyRunnable() {
    }

    @Override
    public void run() {
        System.out.println("子線程ID:"+Thread.currentThread().getId());
    }
}

Thread 與 Runnable 區(qū)別

  • Thread 是線程、而 Runnable 是任務,一個任務可以由多個線程去完成
  • Java 不允許多繼承、因此可實現(xiàn) Runnable 接口在繼承其它類
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容