多線程
一、什麼是程序
程序是系統進行資源配置設定和調用的獨立單元,每一個程序都有它的獨立記憶體空間和系統資源。
二、單程序作業系統和多程序作業系統的差別
單程序作業系統 dos:一次隻能執行單個任務
多程序作業系統 Windows:一次可以執行多個任務
三、系統在同一個時刻可以執行多個任務嗎?
理論上,同一個時刻可以執行多個任務。
因為CPU切換比較快,有的程序正在運作,有的程序正在争搶資源,有的程序正在退出資源
四、什麼是線程,了解線程和程序的關系
什麼是線程?
線程是程序裡面的一條執行路徑,每個線程同享程序裡面的記憶體空間和系統資源
一個程序裡有多線程:各個線程都有不同的分工
了解線程和程序的關系?
程序:程序之間的記憶體空間和系統資源是獨立的
線程:在同一個程序裡的線程之間是共享記憶體空間和系統資源的
程序裡:可以有一條或一條以上的線程
注意:
程序裡隻有一條線程的情況下,這條線程就叫做主線程
程序裡有多條線程的情況下,隻有一條線程叫做主線程
線程是在程序裡的,他們是包裹關系
五、我們應用的軟體有哪些是多線程的應用?
幾乎都是
六、Java中,如何來編寫多線程的應用程式?有哪些方法?
- 線程類
建立步驟:建立MyThread類,繼承Thread,重寫run方法
使用步驟:建立MyThread類的對象,調用start方法
- 任務類
建立步驟:建立Task類,實作Runnable接口,重寫run方法
使用步驟:建立Thread類的對象,并把任務類的對象傳入,調用start方法
- 帶傳回值的任務類
- 線程池
七、體會多線程争搶資源的場景
需求:編寫一個多線程的應用程式,主線程列印1-100之間的數字,子線程列印200-300之間的數字,觀察其輸出的結果,體會多線程互相争搶資源的場景
八、小結
線程類:繼承Thread,重寫run方法,建立線程對象,調用start方法(并非馬上調用run方法)
任務類:實作Runnable接口,重寫run方法,建立任務類對象,通過new Thread(task).start()
主線路從上往下,多線程多條執行路線(随機)
經典面試題:請問當我們編寫一個單純的main方法時,此時該程式是否為單線程的?為什麼?
Java的垃圾回收器是一個背景線程,默默在背景銷毀多餘的對象
九、線程的優先級
需求:在主線程中建立三個的子線程,并且設定不同優先級,觀察其優先級對線程執行結果的影響。
注意:
- 優先級别10-1,10是最進階别,1是最低級别
- 設定優先級别隻能影響結果,不能決定結果
package com.dream.thread04;
public class Test01 {
public static void main(String[] args) {
/**
* 線程的優先級别
*/
//建立線程對象
A a = new A();
B b = new B();
C c = new C();
//設定優先級别
a.setPriority(Thread.MAX_PRIORITY);//最進階别:10
b.setPriority(Thread.NORM_PRIORITY);//預設級别:5
c.setPriority(Thread.MIN_PRIORITY);//最低級别:1
//啟動線程
a.start();
b.start();
c.start();
}
}
十、給線程自定義名稱
package com.dream.thread05;
public class MyThread extends Thread{
public MyThread(String name) {
super(name);
}
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
//Thread.currentThread():擷取目前線程對象
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
十一、線程的休眠
Thread.sleep(1000);休眠目前線程,該方法在哪個線程中調用,就休眠哪個線程
需求: 編寫一個抽取學員回答問題的程式,要求倒數三秒後輸出被抽中的學員姓名
package com.dream.thread06;
import java.util.Random;
public class Test01 {
public static void main(String[] args) throws InterruptedException {
/**
* 線程的休眠
* 需求: 編寫一個抽取學員回答問題的程式,要求倒數三秒後輸出被抽中的學員姓名
*/
Random ran = new Random();
String[] names = {"麻生希","曹桂華","椎名空","北島玲","水菜麗"};
String name = names[ran.nextInt(names.length)];
for (int i = 3; i > 0; i--) {
System.out.println(i);
Thread.sleep(1000);
}
System.out.println(name);
}
}
十二、線程的禮讓
Thread.yield(); 禮讓,寫在哪個線程裡,哪個線程就退出CPU資源,馬上進入到争搶資源的狀态
需求:建立兩個線程A,B,分别各列印100次,從1開始每次增加1,其中B一個線程,每列印一次,就禮讓一次,觀察實驗結果
十三、線程的合并
需求:主線程和子線程各列印200次,從1開始每次增加1,當主線程列印到10之後,讓子線程先列印完再列印主線程
十四、線程的中斷
方式1:自己編寫邏輯使得線程中斷
方式2:
Thread.currentThread().isInterrupted() – 判斷目前線程是否消亡
t.interrupt(); – 改變目前線程狀态
十五、守護線程
含義:守護線程又叫做背景線程,默默守護着前台線程,所有的前台線程消亡後,守護線程自動消亡
注意:垃圾回收器就是一個守護線程
十六、線程局部變量(實作線程範圍内的共享變量)
1.自定義一個靜态變量用于共享
//用靜态變量 concurrenthashMap 作為線程間共享的變量,存儲單個值
//其他類可以通過類名直接擷取,達到共享,通過誰調用就擷取到目前調用線程的對象來存放值。
//線程類通過map,将自己作為key,i作為值放入map
//普通類被線程類的run方法調用,執行成員方法時可以擷取到目前類對象,進而通過map,直接擷取到值。并輸出列印
2.ThreadLocal
低層也是用一個map 來存放資料,通過get()、set()方法擷取或者設定變量,内部是通過Thread.concurrentThread()方法擷取目前線程對象,将目前線程對象作為key,傳入值作為value;
擷取時也是擷取調用線程所對應的key和value
十七、線程的生命周期
a) 建立狀态
i. 在程式中用構造方法建立了一個線程對象後,新的線程對象便處于建立狀态,此時,它已經有了相應的記憶體空間和其它資源,但還處于不可運作狀态。建立一個線程對象可采用線程構造方法來實作。
ii. 例如:Thread thread=new Thread();
b) 就緒狀态
i. 建立線程對象後,調用該線程的start()方法就可以啟動線程。當線程啟動時,線程進入就緒狀态。此時,線程将進入線程隊列排隊,等待CPU調用,這表明它已經具備了運作條件。
c) 運作狀态
i. 當就緒狀态的線程被調用并獲得處理器資源時,線程就進入了運作狀态。此時,自動調用該線程對象的run()方法。run()方法定義了該線程的操作和功能。
d) 阻塞狀态
i. 一個正在執行的線程在某些特殊情況下,如被人為挂起,将讓出CPU并暫時中止自己的執行,進入阻塞狀态。在可執行狀态下,如果調用sleep(2000)、wait()等方法,線程都将進入阻塞狀态。阻塞時,線程不能進入排隊隊列,隻有當引起阻塞的原因被消除後,線程才可以轉入就緒狀态。
e) 死亡狀态
i. 線程調用stop()方法時或run()方法執行結束後,線程即處于死亡狀态。處于死亡狀态的線程不具有繼續運作的能力。
線程的生命周期
Thread.currentThread().isInterrupted();
//判斷目前線程是否被中斷,true-中斷 false-未中斷
//通過Thread類的一個boolean 屬性來判斷目前線程 而不是真正意義上的 中斷
//
Thread.currentThread().interrupt();
修改目前線程的中斷狀态;