Day19、20異常與多執行緒

2020-08-12 20:45:27

異常

概念

異常是程式在執行期發生的不正常的事件,它會打斷指令的正常執行流程。

設計良好的程式應該在異常發生時提供處理這些不正常事件的方法,使程式不會因爲異常的發生而阻斷或產生不可預見的結果。

Java語言使用例外處理機制 機製爲程式提供了例外處理的能力

異常的分類

Java程式執行過程中所發生的異常事件從嚴重性可分爲兩類:

  1. 錯誤(Error):JVM系統內部錯誤或資源耗盡等嚴重情況,屬於JVM需要負擔的責任,這一類異常事件無法恢復或不可能捕獲,將導致應用程式中斷。

  2. 異常(Exception):其它因程式設計錯誤偶然的外在因素導致的一般性問題。這類異常得到恰當的處理時,程式有機會恢復至正常執行狀況。

    1. RuntimeException:又叫做非受檢性異常,編譯器不要求強制處置的異常。一般是指程式設計時的邏輯錯誤。是程式設計師應該積極避免其出現的異常

      RuntimeException/執行時異常/非受檢性異常 描述
      ClassCastException 型別轉換異常
      ArrayIndexOutOfBoundsException 陣列下標越界異常
      NullPointerException 空指針異常
      ArithmeticException 算數類異常
    2. 一般性異常:又叫做受檢性異常,編譯器要求必須處置的異常。指的是程式在執行時由於外界因素造成的一般性異常。

      一般性異常/受檢性異常
      ClassNotFoundException 類的位元組碼檔案未找到異常
      FileNotFoundException 檔案未找到異常
      IOException 操作檔案時異常
      SQLException 數據庫異常

例外處理機制 機製

  1. Java程式在執行過程中如果出現異常,會自動生成一個異常類物件,該異常物件將被自動提交給JVM,這個過程稱爲拋出(throw)異常。
  2. 當JVM接收到異常物件時,會尋找能處理這一異常的程式碼並把當前異常物件交給其處理,這一過程稱爲捕獲(catch)異常和處理異常。
    1. 如果JVM找到可以以捕獲異常的程式碼,將異常物件交給其處理
    2. 如果JVM找不到可以捕獲異常的程式碼,則執行時系統將終止,相應的Java程式也將退出。

例外處理的能力

1.try…catch…

語法:

​ try{

​ //…存放可能發生異常的程式碼…

​ }catch(例外處理的類 e){//捕獲異常

​ //…處理異常…

​ }finally{

​ //不管是否發生異常,finally裡的程式碼塊都會被執行

​ }

注意:finally程式碼塊可以寫可以不寫

2.throws

含義:拋出異常

作用在宣告方法時,拋出該異常物件,讓呼叫方處理

3.throw

含義:拋出異常

作用:可以建立一個異常物件將其拋出

多執行緒

一、什麼是進程

進程是系統進行資源分配和呼叫的獨立單元,每一個進程都有它的獨立的記憶體空間和系統資源。

二、單進程操作系統和多進程操作系統的區別

單進程操作系統:一次只能執行一個任務

多進程操作系統:一次可以執行多個任務

三、現在的多核CPU是否可以讓系統在同一個時刻可以執行多個任務嗎?

理論上是可以的

四、什麼是執行緒,理解執行緒和進程的關係

什麼是執行緒?

執行緒是進程裡的一條執行路徑,每個執行緒同享進程裏面的記憶體空間和系統資源

執行緒和進程的關係?

進程:進程之間的記憶體空間和系統資源是獨立的

執行緒:同一個進程裡的執行緒之間是共用記憶體空間和系統資源的

進程裡:可以有一條或一條以上的執行緒

進程裡只有一條執行緒的情況下,這條執行緒就叫做主執行緒

進程裡有多條執行緒的情況下,只有一條執行緒叫做主執行緒

Ps:執行緒是在進程裡的,他們是包裹關係

五、我們應用的軟體有哪些是多執行緒的應用?

99%都是多執行緒應用

六、Java中,如何來編寫多執行緒的應用程式?有哪些方法?

  1. 執行緒類:建立MyThread類,繼承Thread,重寫run方法

    使用:
    //建立子執行緒
    MyThread t = new MyThread();
    //啓動子執行緒
    t.start();
    
  2. 任務類:建立Task類,實現Runnable介面裏的run方法

    使用:
    //建立子執行緒,並放入任務
    Thread t = new Thread(new Task());
    //啓動子執行緒
    t.start();
    
  3. 帶返回值的任務類

七、體會多執行緒之間爭搶資源的場景

需求:編寫一個多執行緒的應用程式,主執行緒列印1-100之間的數位,子執行緒列印200-300之間的數位,觀察其輸出的結果,體會多執行緒互相爭搶資源的場景

八、小結

使用執行緒類的步驟:

  1. 建立MyThread類,繼承Thread,重寫run方法
  2. 建立MyThread類的物件
  3. 利用物件呼叫start方法

經典面試題:請問當我們編寫一個單純的main方法時,此時該程式是否爲單執行緒的?爲什麼?

不是,是多執行緒程式,當我們執行專案時,Java垃圾回收器也在後台默默執行,垃圾回收器就是一個後臺執行緒

九、執行緒的優先級別

需求:在主執行緒中建立三個的子執行緒,並且設定不同優先順序,觀察其優先順序對執行緒執行結果的」影響」。

優先級別由低到高:1~10

a.setPriority(Thread.MAX_PRIORITY); //10
b.setPriority(Thread.NORM_PRIORITY);//5
c.setPriority(Thread.MIN_PRIORITY);//1

十、給執行緒自定義名稱

利用父類別的構造方法傳入執行緒的名字

通過Thread.currentThread().getName()獲取到當前執行緒的名字

十一、讓執行緒休眠

需求:編寫一個抽取學員回答問題的程式,要求倒數三秒後輸出被抽中的學員姓名

public class Test01 {
	
	public static void main(String[] args) throws InterruptedException {
     
		String[] names = {"小明","小紅","小亮","小飛","小雲"};
		
		Random ran = new Random();
		int randomIndex = ran.nextInt(names.length);
		
		for (int i = 3; i > 0; i--) {
			System.out.println(i);
			Thread.sleep(1000);//休眠1000毫秒
		}
		
		System.out.println(names[randomIndex]);
	}
}

注意:

  1. Thread類的靜態方法
  2. 寫在哪個執行緒裡就休眠當前執行緒

十二、執行緒的禮讓

含義:強制讓當前執行緒退出CPU資源

需求:建立兩個執行緒A,B,分別各列印100次,從1開始每次增加1,其中B一個執行緒,每列印一次,就禮讓一次,觀察實驗結果

public class Test01 {
	
	public static void main(String[] args) {

		new A().start();
		new B().start();
	}
}
class A extends Thread{
	@Override
	public void run() {
		for (int i = 1; i <= 100; i++) {
			System.out.println("A:" + i);
		}
	}
}
class B extends Thread{
	@Override
	public void run() {
		for (int i = 1; i <= 100; i++) {
			System.out.println("B:" + i);
			Thread.yield();//禮讓
		}
	}
}

注意:

  1. Thread類的靜態方法
  2. 寫在哪個執行緒裡就讓當前執行緒退出CPU資源

正確理解禮讓:禮讓後,當前執行緒一定會退出CPU資源,退出後當前執行緒立刻恢復到搶資源的狀態

十三、執行緒的合併

需求:主執行緒和子執行緒各列印200次,從1開始每次增加1,當主執行緒列印到10之後,讓子執行緒先列印完再列印主執行緒

t.join(); --> 讓t執行緒加入到當前執行緒,當前執行緒就阻塞

public class Test01 {
	
	public static void main(String[] args) throws InterruptedException {
		
		MyThread t = new MyThread();
		t.start();
		
		for (int i = 1; i <= 200; i++) {
			System.out.println("主執行緒:" + i);
			if(i == 10){
				t.join();//讓t執行緒加入到當前執行緒,當前執行緒就阻塞
			}
		}
		
	}
}
class MyThread extends Thread{
	
	@Override
	public void run() {
		for (int i = 1; i <= 200; i++) {
			System.out.println("子執行緒:" + i);
		}
	}
}

十四、執行緒的中斷

Thread.currentThread().isInterrupted() 獲取當前執行緒是否死亡

true - 死亡 false-沒有死亡

執行緒物件.interrupt(); 改變執行緒狀態

十五、守護執行緒

含義:守護執行緒又叫做後臺執行緒,守護執行緒默默守護着前臺執行緒,當前台執行緒全部去消亡後,守護執行緒也會自動消亡

執行緒物件.setDaemon(true);//設定當前執行緒爲守護執行緒

垃圾回收器就是一個守護執行緒

十六、執行緒的生命週期

a) 新建狀態

i. 在程式中用構造方法建立了一個執行緒物件後,新的執行緒物件便處於新建狀態,此時,它已經有了相應的記憶體空間和其它資源,但還處於不可執行狀態。新建一個執行緒物件可採用執行緒構造方法來實現。

ii. 例如:Thread thread=new Thread();

b) 就緒狀態

i. 新建執行緒物件後,呼叫該執行緒的start()方法就可以啓動執行緒。當執行緒啓動時,執行緒進入就緒狀態。此時,執行緒將進入執行緒佇列排隊,等待CPU呼叫,這表明它已經具備了執行條件。

c) 執行狀態

i. 當就緒狀態的執行緒被呼叫並獲得處理器資源時,執行緒就進入了執行狀態。此時,自動呼叫該執行緒物件的run()方法。run()方法定義了該執行緒的操作和功能。

d) 阻塞狀態

i. 一個正在執行的執行緒在某些特殊情況下,如被人爲掛起,將讓出CPU並暫時中止自己的執行,進入阻塞狀態。在可執行狀態下,如果呼叫sleep(2000)、wait()等方法,執行緒都將進入阻塞狀態。阻塞時,執行緒不能進入排隊佇列,只有當引起阻塞的原因被消除後,執行緒纔可以轉入就緒狀態。

e) 死亡狀態

執行緒呼叫stop()方法時或run()方法執行結束後,執行緒即處於死亡狀態。處於死亡狀態的執行緒不具有繼續執行的能力。