異常執行緒的相關複習(前)

isccai發表於2020-12-23

異常

當我們執行Java程式碼時,經常會發生一系列的錯誤。異常指的是程式在執行過程中,出現的非正常的情況,最終會導致jvm的非正常停止。
異常的根類是Throwable,它有兩個子類:Exception、Error
* Error:嚴重錯誤Error,無法通過處理的錯誤,只能事先避免,好比絕症。
* Exception:表示異常,異常產生後程式設計師可以通過程式碼的方式糾正,使程式繼續執行,是必須要處理的,好比感冒。
Throwable中常用的方法:
* public void printStackTrace():列印異常的詳細資訊。
包含了異常的型別,異常的原因還包括異常出現的位置在開發和除錯階段都得使用PrintStackTrace
* public String getMessage(): 獲取發生異常的原因。
提示給使用者的時候就提示錯誤原因。
異常的分類:
* 編譯時期異常:checked異常。在編譯時期就會檢查如果沒有處理異常則編譯失敗。
* 執行時期異常:runtime異常。在執行時期,出現異常。
異常的簡單分析:當執行時發生了異常,jvm對於自身認識的異常,並且有相應的描述,描述內容包括:異常的名稱、異常的內容、異常產生的位置。隨後,jvm將產生的異常拋給呼叫者main方法,main方法接受到了異常物件。由於main方法並沒有進行處理異常,main方法就會繼續把異常拋給jvm,當jvm收到異常後,將異常物件中的名稱、異常內容、位置都顯示在列印臺中,同時讓程式立即終止。

異常的處理

  1. 丟擲異常 throws:修飾符 返回值型別 方法名(引數) throws 異常類名1,異常類名2…{ }
  2. 捕獲異常try…catch
try{
	編寫可能會出現異常的程式碼
}catch{
	處理異常的程式碼
}

多執行緒

併發與並行

  • 併發:指的是兩個或多個時間在同一個時間段發生。
  • 並行:指兩個或多個時間在同一時刻發生(同時發生)。

在作業系統中,安裝了多個程式,併發指的是在一段時間內巨集觀上有多個程式同時執行,這在單CPU系統中,每一時刻只能有一道程式執行,即微觀上這些程式是分時的交替執行,只不過是給人的感覺同時執行,那是因為分時交替執行的時間是非常短的。
而在多個CPU系統中,則這些可以併發執行的程式便可以分配到多個處理器上(CPU),實現多工並行執行,即利用每個處理器來處理一個可以併發執行的程式,這樣多個程式便可以同時執行。目前電腦市場上說的多核CPU就是多核處理器,核越多,可以並行的程式越多,能大大的提高電腦執行的效率。
注意:單核處理器的計算機肯定是不能並行的處理多個任務 的,只能是多個任務在單個CPU上併發執行,同理,執行緒也是一樣的,從巨集觀角度上理解執行緒是並行執行的,但是從微觀角度上分析卻是序列執行的,即一個執行緒一個執行緒的執行,當系統只有一個CPU時,執行緒會以某種順序執行多個執行緒,我們把這種情況稱之為執行緒排程。

執行緒與程式

  • 程式:是指一個記憶體中執行的應用程式,每個程式都有一個獨立的記憶體空間,一個應用程式可以同時執行多個程式。程式也是程式的一次執行過程,是系統執行程式的基本單位;系統執行一個程式即是一個程式從建立、執行到消亡的過程。
  • 執行緒:執行緒是程式中的一個執行單元,負責當前程式中程式的執行,一個程式中至少有一個執行緒。一個程式中是可以有多個執行緒的。這個應用程式也可以稱之為多執行緒程式。

執行緒排程:

  • 分時排程:所有執行緒輪流使用CPU的使用權,平均分配每個執行緒佔用CPU的時間。
  • 搶佔式排程:優先讓優先順序高的執行緒使用CPU,如果執行緒的優先順序相同,那麼會隨機選擇一個(執行緒隨機性),Java使用的為搶佔式排程。
  • 搶佔式排程詳解:大部分作業系統都支援多執行緒併發執行,現在的作業系統幾乎都支援同時執行多個程式,例如一遍使用編輯器,一邊使用錄屏軟體等。此時這些程式感覺像是在同一時刻執行著。實際上,CPU(中央處理器)使用搶佔式排程模式在多個執行緒之間進行著高速切換,對於CPU的一個核而言,某個時刻,只能執行一個執行緒,而CPU在多個執行緒間切換速度相對我們的感覺更快,看上去是在同一時刻執行,其實多執行緒程式並不能提高程式的執行速度,但是能夠提高程式執行效率,讓CPU的使用率更高。

建立執行緒類

Java使用 java.lang.Thread類代表執行緒,所有的執行緒物件都必須是Thread類或其子類的例項。每個執行緒的作用是完成一定的任務,實際上就是執行一段程式流,即一段順序執行的程式碼。
通過繼承Thread類來建立並啟動多執行緒的步驟:
1. 定義Thread類的子類,並重寫該類的run方法,該run方法的方法體就代表了執行緒需要完成的任務,因此把run方法稱為執行緒執行體。
2. 建立Thread子類的例項,即建立了執行緒物件。
3. 呼叫執行緒物件的start方法來啟動執行緒
程式碼如下:

測試類:
public class Demo01 {
public static void main(String[] args) {
//建立自定義執行緒物件
MyThread mt = new MyThread("新的執行緒!");
//開啟新執行緒
mt.start();
//在主方法中執行for迴圈
for (int i = 0; i < 10; i++) {
System.out.println("main執行緒!"+i);
		}
	}
}
自定義執行緒類:
public class MyThread extends Thread {
//定義指定執行緒名稱的構造方法
public MyThread(String name) {
//呼叫父類的String引數的構造方法,指定執行緒的名稱
super(name);
}
/**
* 重寫run方法,完成該執行緒執行的邏輯
*/
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(getName()+":正在執行!"+i);
		}
	}
}

程式啟動執行main時候,Java虛擬機器啟動一個程式,主執行緒main在main方法呼叫是被建立,隨著呼叫mt物件的start方法,另外一個新的執行緒也啟動了,這樣整個應用就在多執行緒下執行。
多執行緒執行時,在棧記憶體中,其實每一個執行執行緒都有一片自己所屬的棧記憶體空間。進行方法的壓棧和彈棧。當執行執行緒的任務結束了,執行緒自動在棧記憶體中釋放了,當所有的執行執行緒都結束了,那麼程式就結束了。

Thread類

構造方法
public Thread():分配一個新的執行緒物件。
public Thread(String name):分配一個指定名字的新的執行緒物件。
public Thread(Runnable target):分配一個帶有指定目標新的執行緒物件。
public Thread(Runnable target,String name):分配一個帶有指定目標新的執行緒物件並指定名字。
常用方法
public String getName():獲取當前執行緒名稱。
public void start():導致此執行緒開始執行;Java虛擬機器呼叫此執行緒run方法。
public void run():此執行緒要執行的任務在此處定義程式碼。
public static void sleep (long millis):使當前正在執行的執行緒以指定的毫秒數暫停。
public static Thread currentThread():返回對當前正在執行的執行緒物件的引用。

建立執行緒方式二

用java.lang.Runnable 也是非常常見的一種方式,我們只需要重寫run方法。
步驟:
1. 定義Runnable介面的實現類,並重寫該介面的run方法,該run方法的方法體同樣是該執行緒的執行緒執行體。
2. 建立Runnable實現類的例項,並以此例項作為Thread的target來建立Thread物件,該Thread物件才是真正的執行緒物件。
3. 呼叫執行緒物件的start方法來啟動執行緒。
程式碼如下:

介面實現類:
public class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+" "+i);
		}
	}
}
測試類:
public class Demo {
public static void main(String[] args) {
//建立自定義類物件 執行緒任務物件
MyRunnable mr = new MyRunnable();
//建立執行緒物件
Thread t = new Thread(mr, "小強");
t.start();
for (int i = 0; i < 20; i++) {
System.out.println("旺財 " + i);
		}
	}
}

通過實現Runnable介面,使得該類有了多執行緒的特徵,run方法是多執行緒程式的一個執行,目標,所有的多執行緒程式碼都在run方法裡面。Thread類實際上也是實現了Runnable介面的類。
在啟動多執行緒的時候,需要先通過Thread類的構造方法Thread(Runnable target)構造出物件,然後呼叫Thread物件的start方法來執行多執行緒程式碼。
實際上所有的多執行緒程式碼都是通過執行Thread的方法來執行的,因此不管是繼承Thread類還是實現Runnable介面來實現多執行緒,最終還是通過Thread的物件API來控制多執行緒的,熟悉Thread類的API是進行多執行緒程式設計的基礎。
實現Runnable介面比繼承Thread類所具有的優勢:

  1. 適合多個相同的程式程式碼的執行緒去共享同一個資源。
  2. 可以避免Java中單繼承的侷限性
  3. 增加程式的健壯性,實現解耦操作,程式碼可以被多個執行緒共享,程式碼和執行緒獨立。
  4. 執行緒池只能放入實現Runnable或Callable類執行緒,不能直接放入繼承Thread的類。

題外話

今天寫到這麼晚,不過還是想寫一些題外話。前兩天沒有更新,沒有複習是因為回了趟老家,已經是半年沒有回去了,回去發現,爸媽年邁了許多,頭髮白了許多,看到他們滄桑的臉龐真的有點震驚了,不知道為什麼人會倉老的這麼快。也許是因為他們太累了,可能也有很多的事情發愁。我自己是農村出生的,家裡的爸媽都是做著農活,父親偶爾會在工地中做做臨時工。每次想起父母的這些辛勞,心中就慢慢開始苦澀起來,並且下定決心自己以後一定要好好工作,讓父母下半輩子過不一樣的生活。看到父親還是那樣淳樸的眼神,雖然脾氣不太好,但是真的是農村人的淳樸展現的淋漓盡致,母親還是像一樣,無微不至的照顧我,做好吃的給我吃,像以前一樣每次回去都說我瘦了好多。本來這些東西是不打算寫在這邊的,但是想到這裡是記錄我成長的過程,也能加入一些其他的元素,也是記錄生活的一種方式,反正看得人也少,就當做是寫一篇簡短日記了。

相關文章