多線程概述
- 多線程是指一個進程(執(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 接口在繼承其它類
