作業系統支援多個應用程式並行執行,每個應用程式至少對應一個程序 ,彼此之間的操作和資料不受干擾,彼此通訊一般採用管道通訊、訊息佇列、共用記憶體等方式。當一個程序需要磁碟IO的時候,CPU就切換到另外的程序,提高了CPU利用率。
有了程序,為什麼還要執行緒?因為程序的成本太高了。
啟動新的程序必須分配獨立的記憶體空間,建立資料表維護它的程式碼段、堆疊段和資料段,這是昂貴的多工工作方式。執行緒可以看作輕量化的程序。執行緒之間使用相同的地址空間,切換執行緒的時間遠小於切換程序的時間。
程序是資源分配的最小單位,而執行緒是CPU排程的最小單位。每一個程序中至少有一個執行緒,同一程序的所有執行緒共用該程序的所有資源,多個執行緒可以完成多個不同的任務,也就是我們常說的並行多執行緒。
建立執行緒常用的有四種方式,分別是:
分別看一下怎麼具體怎麼使用程式碼建立的?
public class ThreadDemo {
public static void main(String[] args) {
Thread thread = new MyThread();
thread.start(); // 啟動執行緒
}
}
class MyThread extends Thread {
@Override
public void run() {
System.out.println("關注公眾號:一燈架構");
}
}
輸出結果:
關注公眾號:一燈架構
start方法用來啟動執行緒,只能被呼叫一次。
run方法是執行緒的核心方法,業務邏輯都寫在run方法中。
public class ThreadDemo {
public static void main(String[] args) {
MyRunnable myRunnable = new MyRunnable();
Thread thread1 = new Thread(myRunnable, "執行緒1");
Thread thread2 = new Thread(myRunnable, "執行緒2");
thread1.start(); // 啟動執行緒1
thread2.start(); // 啟動執行緒2
}
}
class MyRunnable implements Runnable {
private int count = 5;
@Override
public void run() {
while (count > 0) {
System.out.println(Thread.currentThread().getName()
+ ",關注公眾號:一燈架構," + count--);
}
}
}
輸出結果:
執行緒2,關注公眾號:一燈架構,4
執行緒1,關注公眾號:一燈架構,5
執行緒1,關注公眾號:一燈架構,2
執行緒1,關注公眾號:一燈架構,1
執行緒2,關注公眾號:一燈架構,3
需要把Runnable範例放到Thread類中,才能執行,Thread物件才是真正的執行緒物件。
使用實現Runnable介面建立執行緒方式,相比繼承Thread類建立執行緒,優點是:
public class ThreadTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
MyCallable myCallable = new MyCallable();
FutureTask<String> futureTask = new FutureTask<String>(myCallable);
Thread thread = new Thread(futureTask);
thread.start();
System.out.println(futureTask.get());
}
}
class MyCallable implements Callable {
@Override
public String call() throws Exception {
return "關注公眾號:一燈架構";
}
}
輸出結果:
關注公眾號:一燈架構
實現Callable介面的執行緒範例物件,配合FutureTask使用,可以接收返回值。
public class ThreadDemo {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(10);
executorService.execute(() -> System.out.println("關注公眾號:一燈架構"));
}
}
輸出結果:
關注公眾號:一燈架構
使用執行緒池建立執行緒是工作開發中最常用的方式,優點是:
執行緒共有6種狀態,分別是NEW(初始化)、RUNNABLE(可執行)、WAITING(等待)、TIMED_WAITING(超時等待)、BLOCKED(阻塞)、TERMINATED(終止)。
NEW(初始化)
表示建立執行緒物件之後,還沒有呼叫start方法。
RUNNABLE(可執行)
表示呼叫start方法之後,等待CPU排程。為了便於理解,通常又把RUNNABLE分別RUNNING(執行中)和READY(就緒)。處在RUNNING(執行中)狀態的執行緒可以呼叫yield方法,讓出CPU時間片,然後跟其他處於READY(就緒)一起等待被排程。
WAITING(等待)
處於RUNNABLE狀態的執行緒呼叫wait方法之後,就處於等待狀態,需要其他執行緒顯示地喚醒。
TIMED_WAITING(超時等待)
處於RUNNABLE狀態的執行緒呼叫wait(long)方法之後,就處於等待狀態,需要其他執行緒顯示地喚醒。
BLOCKED(阻塞)
等待進入synchronized方法/程式碼塊,處於阻塞狀態。
TERMINATED(終止)
表示執行緒已經執行結束。
說一下執行緒有哪些常用的方法。
方法定義 | 含義 | 使用方式 |
---|---|---|
public synchronized void start() {……} | 啟動執行緒 | MyThread myThread = new MyThread(); myThread.start(); |
public static native Thread currentThread(); | 獲取當前執行緒範例物件 | Thread thread = Thread.currentThread(); |
public static native void yield(); | 讓出CPU時間片 | Thread.yield(); |
public static native void sleep(long millis); | 睡眠指定時間 | Thread.sleep(1L); |
public void interrupt() {……} | 中斷執行緒 | MyThread myThread = new MyThread(); myThread.interrupt(); |
public static boolean interrupted() {……} | 判斷執行緒是否已中斷 | MyThread myThread = new MyThread(); boolean interrupted = myThread.isInterrupted(); |
public final native boolean isAlive(); | 判斷執行緒是否是存活狀態 | MyThread myThread = new MyThread(); boolean alive = myThread.isAlive(); |
public final String getName() {……} | 獲取執行緒名稱 | MyThread myThread = new MyThread(); String name = myThread.getName(); |
public State getState() {……} | 獲取執行緒狀態 | MyThread myThread = new MyThread(); Thread.State state = myThread.getState(); |
public long getId() {……} | 獲取執行緒ID | MyThread myThread = new MyThread(); long id = myThread.getId(); |
public final void join() {……} | 等待其他執行緒執行完再執行 | MyThread myThread = new MyThread(); myThread.join(); |
我是「一燈架構」,如果本文對你有幫助,歡迎各位小夥伴點贊、評論和關注,感謝各位老鐵,我們下期見