day31-執行緒基礎01
執行緒基礎01
1.程式 進程 執行緒
- 程式(program):是為完成的特定任務,用某種語言編寫的一組指令的集合。簡單來說,就是我們寫的程式碼。
-
進程:
- 進程是指運行中的程式,比如我們使用QQ,就啟動了一個進程,作業系統就會為該進程分配空間。當我們使用迅雷,又啟動了一個進程,作業系統將為迅雷分配新的記憶體空間。
- 進程是程式的一次執行過程,或是正在運行的一個程式。是動態過程:有它自身的產生、存在和消亡的過程。
-
執行緒:
- 執行緒是由進程創建的,是進程的一個實體
- 一個進程可以有多個執行緒,比如:用迅雷同時下載多個文件
-
其他相關概念:
- 單執行緒:同一時刻,只允許執行一個執行緒
- 多執行緒:同一時刻,可以執行多個執行緒,比如:一個qq進程,可以同時打開多個聊天窗口;一個迅雷進程,可以同時下載多個文件。
- 並發:同一時刻,多個任務交替執行,造成一種「貌似同時」的錯覺,簡單地說,單核cpu實現的多任務就是並發
- 並行:同一時刻,多個任務同時執行。多核cpu可以實現並行。在電腦中也可能同時出現並發和並行的狀態。
例子:
package li.thread;
public class CpuNum {
public static void main(String[] args) {
Runtime runtime = Runtime.getRuntime();
//獲取當前的電腦的cpu數量
int cpuNums = runtime.availableProcessors();
System.out.println("當前的CPU數量="+cpuNums);//當前的CPU數量=8
}
}
2.執行緒的基本使用
- 創建執行緒的兩種方式
在java中執行緒來使用有兩種方法:
- 繼承Thread類,重寫run方法
- 實現Runnable介面,重寫run方法
2.1繼承Thread創建執行緒
例子1:執行緒應用案例1-繼承Thread類
1)請編寫程式,開啟一個執行緒,該執行緒每隔一秒,在控制台輸出 「喵喵,我是小貓咪」
2)對上題改進:當輸出80次「喵喵,我是小貓咪」時,結束該執行緒
3)使用JConsole監控執行緒執行情況,並畫出程式示意圖
package li.thread;
//演示通過繼承Thread類創建執行緒
public class Thread01 {
public static void main(String[] args) throws InterruptedException {
//創建一個Cat對象,可以當做執行緒來使用
Cat cat = new Cat();
cat.start();//啟動執行緒
//當main執行緒啟動一個子執行緒 Thread-0後,主執行緒不會阻塞,會繼續執行
//這時 主執行緒和子執行緒是交替執行
System.out.println("主執行緒繼續執行="+Thread.currentThread().getName());//主執行緒繼續執行=main
for (int i = 0; i < 60; i++) {
System.out.println("主執行緒 i="+i);
//讓主執行緒休眠
Thread.sleep(1000);
}
}
}
//1.當一個類繼承了Thread類,該類就可以當做一個執行緒使用
//2.我們會重寫run方法,寫上自己的業務程式碼
//3.run Thread類實現了Runnable介面的run方法
/*
@Override
public void run() {
if (target != null) {
target.run();
}
}
*/
class Cat extends Thread {
@Override
public void run() {//重寫run方法,寫上自己的業務邏輯
int times = 0;
while (true) {
//該執行緒每隔1秒,在控制台輸出 「喵喵,我是小貓咪」
System.out.println("喵喵,我是小貓咪" + (++times)+" 執行緒名稱="+Thread.currentThread().getName());
//讓該執行緒休眠一秒
try {
Thread.sleep(1000);//單位為毫秒 try-catch快捷鍵:Ctrl+Alt+T
} catch (InterruptedException e) {
e.printStackTrace();
}
if (times == 80) {
break;//當times到80,退出while,這是執行緒也就退出了
}
}
}
}
3)使用JConsole監控執行緒執行情況,並畫出程式示意圖:
如下,在控制台點擊run,運行程式,在程式運行時,點擊Termial
在控制台輸入JConsole,回車。
點擊本地進程,點擊Thread01,點擊下方連接按鈕:
在彈出窗口中點擊不安全的連接按鈕:
在窗口中點擊「執行緒」:
可以在左下角的執行緒小窗口中看到main執行緒和Thread-0執行緒在同時進行
等待一段時間,可以看到當run窗口的主執行緒 i = 60之後,main執行緒結束
結束前:
結束後:
當執行緒名稱=Thread-0輸出到80次時,雖然可以Thread-0還在左下角,但是實際上Thread-0執行緒已經結束了,整個進程隨之結束。
程式示意圖:
注意:在多執行緒編程裡面,並不一定說主執行緒結束了,整個進行就結束了,等所有執行緒都結束了,進程才會結束。
2.2為什麼是start?
在2.1的例子中,主方法中定義了cat對象,該對象調用了start方法,start方法會去啟動一個執行緒,最終會執行Cat 類的run方法。
思考一個問題:既然最終都是要調用run方法,為什麼cat對象還要通過start方法對調用run呢?為什麼不直接調用?
答案: 首先通過 對象.run() 方法 可以執行方法,但是不是使用的多執行緒的方式,就是一個普通的方法,沒有真正地啟動一個執行緒。即這時候把run方法執行完畢,才能執行主方法剩下的語句。
如下圖:將cat.start();
改為cat.run();
之後的運行結果:
在run方法執行完之後才執行主方法剩下的語句
那麼在調用start方法時,整個過程到底是什麼樣子的?
點擊start()方法:可以在start方法中看到一個start0()方法:
點擊start0( )方法:可以看到start0是一個本地方法,由 JVM調用,底層是c/c++實現。
再看看run()方法的源碼:可以看到run方法只是簡單的調用了實現類的run,沒有進行任何的多執行緒處理。
換而言之,Java中真正實現多執行緒的效果的是start0方法,而不是run方法