多線程的概念
進程是程序運行的實例。啓動一個java程序其實就是啓動了一個jvm的進程。進程是程序向操作系統申請資源(內存空間、文件句柄等)
的基本單位。
線程是進程中可以獨立執行的最小單位。
進程和線程的關係,可以比喻成一個項目組和組員的關係。項目組完成一個項目需要需求,開發,測試。這些往往都是並行的。需要需求,開發和測試人員協作完成。他們共享項目組的資源,如需求文檔,功能代碼等。
爲什麼需要線程
- 提高cpu的利用率。因爲cpu的執行速率是遠遠高於io操作的。如果單線程運行,遇到io操作,系統會一直等待io完成再往下執行。這段io操作的時間內浪費了cpu的性能。
- 提高響應速率。爲了用戶的體驗,在使用GUI軟件時,一個慢的IO操作不至於會使軟件"凍住"。
- 充分利用多核。對應已經普及的多核計算機,多線程可以重複利用其性能。
java中的線程
java中的線程是通過java.lang.Thread類來實現。一個Thread或其子類就是一個線程。
創建線程
創建執行線程的方式有三種:
Thread類的構造函數大概可以分爲要Runnable和不需要Runnable兩種。 Thread()和 Thread(Runnable)。所以可以根據這兩種方式來創建一個線程。
- 繼承Thread
//1.繼承Thread類
class ThreadDemo extends Thread{
//2.重寫run方法。
public void run() {
// 業務邏輯
}
}
public static void main(String[] args) {
//new 一個Thread對象
Thread thread = new ThreadDemo();
//調用start方法啓動一個線程。線程啓動後會執行run方法。
thread.start();
}
- 實現Runnable接口
//1.實現Runnable類
class RunnableDemo implements Runnable{
//2.實現run方法
public void run() {
// 業務邏輯
}
}
public static void main(String[] args) {
//new 一Runnable實現類
Runnable run = new RunnableDemo();
//通過Runnable構造Thread
Thread thread2 = new Thread(run);
//啓動線程
thread2.start();
}
上面兩種線程都沒有返回值,jdk1.5後出現了callable能創建具有返回值的線程。
//實現Callable接口
class CallableDemo implements Callable<String>{
//實現call方法
public String call() throws Exception {
return "callable";
}
}
public static void main(String[] args) {
//callable有兩種使用方式:
//1.通過線程池
//創建線程池
ExecutorService threadService = Executors.newSingleThreadExecutor();
//提交callable任務
Future<String> submit = threadService.submit(new CallableDemo());
//阻塞獲取返回值
String object = submit.get();
System.out.println(object);
//2. 通過FutureTask
FutureTask<String> task1 = new FutureTask<String>(new CallableDemo() {
});
Thread thread1 = new Thread(task1);
thread1.start();
System.out.println(task1.get());
}
三種創建線程方式的差異
callable和runnable除了callable可以有返回值,其他的都一樣。實際上callable最終會被構造成一個實現Runnable結構的類。例如上面的FutureTask。
主要分析Runnable方式和繼承Thread這兩種方式。
-
繼承Thread是通過繼承的方式,實現Runnable是一種組合的方式。組合相對於繼承更加低耦合和靈活。《Effictive java》中也提到複合優先於繼承的觀點。
-
實現Runnable的方式,容易線程間實現資源的共享。因爲一個Runnable對象可以用來創建多個線程。對象的成員變量被多個線程共享。這也使得我們要注意線程安全問題。
線程的屬性
屬性 | 作用 |
---|---|
編號(ID) | 用於標識不同線程 |
名稱(Name) | 用於區分不同線程 默認:"thread-0" .可以設置。 |
線程類別(Daemon) | 可以設置守護線程。主線程結束,守護線程也會結束 |
優先級(Priority) | 可以設置線程優先級,1-10.默認5. |
線程的狀態
借圖:
狀態 | 說明 |
---|---|
創建(New) | 線程被創建未啓動。java中就是還沒調用start方法之前 |
可運行(Runnable) | 該狀態下有兩種情況,一種是獲取到cpu的時間片 |
阻塞(BLOCKED) | 發起阻塞IO或者爭取獨佔鎖資源。該狀態不佔用cpu |
等待(Waiting) | 執行特定的方法會,等待其他線程喚醒 |
有時限等待(Timed Waiting) | 和Waiting狀態類似,但是Timed Waiting是有時限的,指定時間到會結束等待狀態 |
消亡(Terminated) | run方法執行完畢或者發生異常。 |