05-异常,线程
聲明:此博客來(lái)自于黑馬程序員學(xué)習(xí)筆記,并非商用,僅僅是為了博主個(gè)人日后學(xué)習(xí)復(fù)習(xí)用,如有冒犯,請(qǐng)聯(lián)系qq208820388立即刪除博文,最后,來(lái)跟我一起喊黑馬牛逼黑馬牛逼黑馬牛逼
【異常、線程】
文章目錄
- 【異常、線程】
- 主要內(nèi)容
- 教學(xué)目標(biāo)
- 第一章 異常
- 1.1 異常概念
- 1.2 異常體系
- 1.3 異常分類(lèi)
- 1.4 異常的產(chǎn)生過(guò)程解析
- 第二章 異常的處理
- 2.1 拋出異常throw
- 2.2 Objects非空判斷
- 2.3 聲明異常throws
- 2.4 捕獲異常try…catch
- 2.4 finally 代碼塊
- 2.5 異常注意事項(xiàng)
- 第三章 自定義異常
- 3.1 概述
- 3.2 自定義異常的練習(xí)
- 第四章 多線程
- 4.1 并發(fā)與并行
- 4.2 線程與進(jìn)程
- 4.3 創(chuàng)建線程類(lèi)
主要內(nèi)容
- 異常、線程
教學(xué)目標(biāo)
- 能夠辨別程序中異常和錯(cuò)誤的區(qū)別
- 說(shuō)出異常的分類(lèi)
- 說(shuō)出虛擬機(jī)處理異常的方式
- 列舉出常見(jiàn)的三個(gè)運(yùn)行期異常
- 能夠使用try…catch關(guān)鍵字處理異常
- 能夠使用throws關(guān)鍵字處理異常
- 能夠自定義異常類(lèi)
- 能夠處理自定義異常類(lèi)
- 說(shuō)出進(jìn)程的概念
- 說(shuō)出線程的概念
- 能夠理解并發(fā)與并行的區(qū)別
- 能夠開(kāi)啟新線程
第一章 異常
1.1 異常概念
異常,就是不正常的意思。在生活中:醫(yī)生說(shuō),你的身體某個(gè)部位有異常,該部位和正常相比有點(diǎn)不同,該部位的功能將受影響.在程序中的意思就是:
- 異常 :指的是程序在執(zhí)行過(guò)程中,出現(xiàn)的非正常的情況,最終會(huì)導(dǎo)致JVM的非正常停止。
在Java等面向?qū)ο蟮木幊陶Z(yǔ)言中,異常本身是一個(gè)類(lèi),產(chǎn)生異常就是創(chuàng)建異常對(duì)象并拋出了一個(gè)異常對(duì)象。Java處理異常的方式是中斷處理。
異常指的并不是語(yǔ)法錯(cuò)誤,語(yǔ)法錯(cuò)了,編譯不通過(guò),不會(huì)產(chǎn)生字節(jié)碼文件,根本不能運(yùn)行.
1.2 異常體系
異常機(jī)制其實(shí)是幫助我們找到程序中的問(wèn)題,異常的根類(lèi)是java.lang.Throwable,其下有兩個(gè)子類(lèi):java.lang.Error與java.lang.Exception,平常所說(shuō)的異常指java.lang.Exception。
Throwable體系:
- Error:嚴(yán)重錯(cuò)誤Error,無(wú)法通過(guò)處理的錯(cuò)誤,只能事先避免,好比絕癥。
- Exception:表示異常,異常產(chǎn)生后程序員可以通過(guò)代碼的方式糾正,使程序繼續(xù)運(yùn)行,是必須要處理的。好比感冒、闌尾炎。
Throwable中的常用方法:
-
public void printStackTrace():打印異常的詳細(xì)信息。
包含了異常的類(lèi)型,異常的原因,還包括異常出現(xiàn)的位置,在開(kāi)發(fā)和調(diào)試階段,都得使用printStackTrace。
-
public String getMessage():獲取發(fā)生異常的原因。
提示給用戶的時(shí)候,就提示錯(cuò)誤原因。
-
public String toString():獲取異常的類(lèi)型和異常描述信息(不用)。
出現(xiàn)異常,不要緊張,把異常的簡(jiǎn)單類(lèi)名,拷貝到API中去查。
1.3 異常分類(lèi)
我們平常說(shuō)的異常就是指Exception,因?yàn)檫@類(lèi)異常一旦出現(xiàn),我們就要對(duì)代碼進(jìn)行更正,修復(fù)程序。
異常(Exception)的分類(lèi):根據(jù)在編譯時(shí)期還是運(yùn)行時(shí)期去檢查異常?
- 編譯時(shí)期異常:checked異常。在編譯時(shí)期,就會(huì)檢查,如果沒(méi)有處理異常,則編譯失敗。(如日期格式化異常)
- 運(yùn)行時(shí)期異常:runtime異常。在運(yùn)行時(shí)期,檢查異常.在編譯時(shí)期,運(yùn)行異常不會(huì)編譯器檢測(cè)(不報(bào)錯(cuò))。(如數(shù)學(xué)異常)
?
1.4 異常的產(chǎn)生過(guò)程解析
先運(yùn)行下面的程序,程序會(huì)產(chǎn)生一個(gè)數(shù)組索引越界異常ArrayIndexOfBoundsException。我們通過(guò)圖解來(lái)解析下異常產(chǎn)生的過(guò)程。
工具類(lèi)
public class ArrayTools {// 對(duì)給定的數(shù)組通過(guò)給定的角標(biāo)獲取元素。public static int getElement(int[] arr, int index) {int element = arr[index];return element;} }測(cè)試類(lèi)
public class ExceptionDemo {public static void main(String[] args) {int[] arr = { 34, 12, 67 };intnum = ArrayTools.getElement(arr, 4)System.out.println("num=" + num);System.out.println("over");} }上述程序執(zhí)行過(guò)程圖解:
第二章 異常的處理
Java異常處理的五個(gè)關(guān)鍵字:try、catch、finally、throw、throws
2.1 拋出異常throw
在編寫(xiě)程序時(shí),我們必須要考慮程序出現(xiàn)問(wèn)題的情況。比如,在定義方法時(shí),方法需要接受參數(shù)。那么,當(dāng)調(diào)用方法使用接受到的參數(shù)時(shí),首先需要先對(duì)參數(shù)數(shù)據(jù)進(jìn)行合法的判斷,數(shù)據(jù)若不合法,就應(yīng)該告訴調(diào)用者,傳遞合法的數(shù)據(jù)進(jìn)來(lái)。這時(shí)需要使用拋出異常的方式來(lái)告訴調(diào)用者。
在java中,提供了一個(gè)throw關(guān)鍵字,它用來(lái)拋出一個(gè)指定的異常對(duì)象。那么,拋出一個(gè)異常具體如何操作呢?
創(chuàng)建一個(gè)異常對(duì)象。封裝一些提示信息(信息可以自己編寫(xiě))。
需要將這個(gè)異常對(duì)象告知給調(diào)用者。怎么告知呢?怎么將這個(gè)異常對(duì)象傳遞到調(diào)用者處呢?通過(guò)關(guān)鍵字throw就可以完成。throw 異常對(duì)象。
throw用在方法內(nèi),用來(lái)拋出一個(gè)異常對(duì)象,將這個(gè)異常對(duì)象傳遞到調(diào)用者處,并結(jié)束當(dāng)前方法的執(zhí)行。
使用格式:
throw new 異常類(lèi)名(參數(shù));例如:
throw new NullPointerException("要訪問(wèn)的arr數(shù)組不存在");throw new ArrayIndexOutOfBoundsException("該索引在數(shù)組中不存在,已超出范圍");學(xué)習(xí)完拋出異常的格式后,我們通過(guò)下面程序演示下throw的使用。
public class ThrowDemo {public static void main(String[] args) {//創(chuàng)建一個(gè)數(shù)組 int[] arr = {2,4,52,2};//根據(jù)索引找對(duì)應(yīng)的元素 int index = 4;int element = getElement(arr, index);System.out.println(element);System.out.println("over");}/** 根據(jù) 索引找到數(shù)組中對(duì)應(yīng)的元素*/public static int getElement(int[] arr,int index){ //判斷 索引是否越界if(index<0 || index>arr.length-1){/*判斷條件如果滿足,當(dāng)執(zhí)行完throw拋出異常對(duì)象后,方法已經(jīng)無(wú)法繼續(xù)運(yùn)算。這時(shí)就會(huì)結(jié)束當(dāng)前方法的執(zhí)行,并將異常告知給調(diào)用者。這時(shí)就需要通過(guò)異常來(lái)解決。 */throw new ArrayIndexOutOfBoundsException("哥們,角標(biāo)越界了~~~");}int element = arr[index];return element;} }注意:如果產(chǎn)生了問(wèn)題,我們就會(huì)throw將問(wèn)題描述類(lèi)即異常進(jìn)行拋出,也就是將問(wèn)題返回給該方法的調(diào)用者。
那么對(duì)于調(diào)用者來(lái)說(shuō),該怎么處理呢?一種是進(jìn)行捕獲處理,另一種就是繼續(xù)講問(wèn)題聲明出去,使用throws聲明處理。
2.2 Objects非空判斷
還記得我們學(xué)習(xí)過(guò)一個(gè)類(lèi)Objects嗎,曾經(jīng)提到過(guò)它由一些靜態(tài)的實(shí)用方法組成,這些方法是null-save(空指針安全的)或null-tolerant(容忍空指針的),那么在它的源碼中,對(duì)對(duì)象為null的值進(jìn)行了拋出異常操作。
- public static <T> T requireNonNull(T obj):查看指定引用對(duì)象不是null。
查看源碼發(fā)現(xiàn)這里對(duì)為null的進(jìn)行了拋出異常操作:
public static <T> T requireNonNull(T obj) {if (obj == null)throw new NullPointerException();return obj; }2.3 聲明異常throws
聲明異常:將問(wèn)題標(biāo)識(shí)出來(lái),報(bào)告給調(diào)用者。如果方法內(nèi)通過(guò)throw拋出了編譯時(shí)異常,而沒(méi)有捕獲處理(稍后講解該方式),那么必須通過(guò)throws進(jìn)行聲明,讓調(diào)用者去處理。
關(guān)鍵字throws運(yùn)用于方法聲明之上,用于表示當(dāng)前方法不處理異常,而是提醒該方法的調(diào)用者來(lái)處理異常(拋出異常).
聲明異常格式:
修飾符 返回值類(lèi)型 方法名(參數(shù)) throws 異常類(lèi)名1,異常類(lèi)名2…{ }聲明異常的代碼演示:
public class ThrowsDemo {public static void main(String[] args) throws FileNotFoundException {read("a.txt");}// 如果定義功能時(shí)有問(wèn)題發(fā)生需要報(bào)告給調(diào)用者。可以通過(guò)在方法上使用throws關(guān)鍵字進(jìn)行聲明public static void read(String path) throws FileNotFoundException {if (!path.equals("a.txt")) {//如果不是 a.txt這個(gè)文件 // 我假設(shè) 如果不是 a.txt 認(rèn)為 該文件不存在 是一個(gè)錯(cuò)誤 也就是異常 throwthrow new FileNotFoundException("文件不存在");}} }throws用于進(jìn)行異常類(lèi)的聲明,若該方法可能有多種異常情況產(chǎn)生,那么在throws后面可以寫(xiě)多個(gè)異常類(lèi),用逗號(hào)隔開(kāi)。
public class ThrowsDemo2 {public static void main(String[] args) throws IOException {read("a.txt");}public static void read(String path)throws FileNotFoundException, IOException {if (!path.equals("a.txt")) {//如果不是 a.txt這個(gè)文件 // 我假設(shè) 如果不是 a.txt 認(rèn)為 該文件不存在 是一個(gè)錯(cuò)誤 也就是異常 throwthrow new FileNotFoundException("文件不存在");}if (!path.equals("b.txt")) {throw new IOException();}} }完整代碼示例:
package com.itheima.demo01.Exception;import java.io.FileNotFoundException; import java.io.IOException;/*throws關(guān)鍵字:異常處理的第一種方式,交給別人處理作用:當(dāng)方法內(nèi)部拋出異常對(duì)象的時(shí)候,那么我們就必須處理這個(gè)異常對(duì)象可以使用throws關(guān)鍵字處理異常對(duì)象,會(huì)把異常對(duì)象聲明拋出給方法的調(diào)用者處理(自己不處理,給別人處理),最終交給JVM處理-->中斷處理使用格式:在方法聲明時(shí)使用修飾符 返回值類(lèi)型 方法名(參數(shù)列表) throws AAAExcepiton,BBBExcepiton...{throw new AAAExcepiton("產(chǎn)生原因");throw new BBBExcepiton("產(chǎn)生原因");...}注意:1.throws關(guān)鍵字必須寫(xiě)在方法聲明處2.throws關(guān)鍵字后邊聲明的異常必須是Exception或者是Exception的子類(lèi)3.方法內(nèi)部如果拋出了多個(gè)異常對(duì)象,那么throws后邊必須也聲明多個(gè)異常如果拋出的多個(gè)異常對(duì)象有子父類(lèi)關(guān)系,那么直接聲明父類(lèi)異常即可4.調(diào)用了一個(gè)聲明拋出異常的方法,我們就必須的處理聲明的異常要么繼續(xù)使用throws聲明拋出,交給方法的調(diào)用者處理,最終交給JVM要么try...catch自己處理異常*/ public class Demo05Throws {/*FileNotFoundException extends IOException extends Excepiton如果拋出的多個(gè)異常對(duì)象有子父類(lèi)關(guān)系,那么直接聲明父類(lèi)異常即可*///public static void main(String[] args) throws FileNotFoundException,IOException {//public static void main(String[] args) throws IOException {public static void main(String[] args) throws Exception {readFile("c:\\a.tx");System.out.println("后續(xù)代碼");}/*定義一個(gè)方法,對(duì)傳遞的文件路徑進(jìn)行合法性判斷如果路徑不是"c:\\a.txt",那么我們就拋出文件找不到異常對(duì)象,告知方法的調(diào)用者注意:FileNotFoundException是編譯異常,拋出了編譯異常,就必須處理這個(gè)異常可以使用throws繼續(xù)聲明拋出FileNotFoundException這個(gè)異常對(duì)象,讓方法的調(diào)用者處理*/public static void readFile(String fileName) throws FileNotFoundException,IOException{if(!fileName.equals("c:\\a.txt")){throw new FileNotFoundException("傳遞的文件路徑不是c:\\a.txt");}/*如果傳遞的路徑,不是.txt結(jié)尾那么我們就拋出IO異常對(duì)象,告知方法的調(diào)用者,文件的后綴名不對(duì)*/if(!fileName.endsWith(".txt")){throw new IOException("文件的后綴名不對(duì)");}System.out.println("路徑?jīng)]有問(wèn)題,讀取文件");} }2.4 捕獲異常try…catch
如果異常出現(xiàn)的話,會(huì)立刻終止程序,所以我們得處理異常:
try-catch的方式就是捕獲異常。
- 捕獲異常:Java中對(duì)異常有針對(duì)性的語(yǔ)句進(jìn)行捕獲,可以對(duì)出現(xiàn)的異常進(jìn)行指定方式的處理。
捕獲異常語(yǔ)法如下:
try{編寫(xiě)可能會(huì)出現(xiàn)異常的代碼 }catch(異常類(lèi)型 e){處理異常的代碼//記錄日志/打印異常信息/繼續(xù)拋出異常 }**try:**該代碼塊中編寫(xiě)可能產(chǎn)生異常的代碼。
**catch:**用來(lái)進(jìn)行某種異常的捕獲,實(shí)現(xiàn)對(duì)捕獲到的異常進(jìn)行處理。
注意:try和catch都不能單獨(dú)使用,必須連用。
演示如下:
public class TryCatchDemo {public static void main(String[] args) {try {// 當(dāng)產(chǎn)生異常時(shí),必須有處理方式。要么捕獲,要么聲明。read("b.txt");} catch (FileNotFoundException e) {// 括號(hào)中需要定義什么呢?//try中拋出的是什么異常,在括號(hào)中就定義什么異常類(lèi)型System.out.println(e);}System.out.println("over");}/*** 我們 當(dāng)前的這個(gè)方法中 有異常 有編譯期異常*/public static void read(String path) throws FileNotFoundException {if (!path.equals("a.txt")) {//如果不是 a.txt這個(gè)文件 // 我假設(shè) 如果不是 a.txt 認(rèn)為 該文件不存在 是一個(gè)錯(cuò)誤 也就是異常 throwthrow new FileNotFoundException("文件不存在");}} }如何獲取異常信息:
Throwable類(lèi)中定義了一些查看方法:
-
public String getMessage():獲取異常的描述信息,原因(提示給用戶的時(shí)候,就提示錯(cuò)誤原因。
-
public String toString():獲取異常的類(lèi)型和異常描述信息(不用)。
-
public void printStackTrace():打印異常的跟蹤棧信息并輸出到控制臺(tái)。
? 包含了異常的類(lèi)型,異常的原因,還包括異常出現(xiàn)的位置,在開(kāi)發(fā)和調(diào)試階段,都得使用printStackTrace。
2.4 finally 代碼塊
finally:有一些特定的代碼無(wú)論異常是否發(fā)生,都需要執(zhí)行。另外,因?yàn)楫惓?huì)引發(fā)程序跳轉(zhuǎn),導(dǎo)致有些語(yǔ)句執(zhí)行不到。而finally就是解決這個(gè)問(wèn)題的,在finally代碼塊中存放的代碼都是一定會(huì)被執(zhí)行的。
什么時(shí)候的代碼必須最終執(zhí)行?
當(dāng)我們?cè)趖ry語(yǔ)句塊中打開(kāi)了一些物理資源(磁盤(pán)文件/網(wǎng)絡(luò)連接/數(shù)據(jù)庫(kù)連接等),我們都得在使用完之后,最終關(guān)閉打開(kāi)的資源。
finally的語(yǔ)法:
try…catch…finally:自身需要處理異常,最終還得關(guān)閉資源。
注意:finally不能單獨(dú)使用。
比如在我們之后學(xué)習(xí)的IO流中,當(dāng)打開(kāi)了一個(gè)關(guān)聯(lián)文件的資源,最后程序不管結(jié)果如何,都需要把這個(gè)資源關(guān)閉掉。
finally代碼參考如下:
public class TryCatchDemo4 {public static void main(String[] args) {try {read("a.txt");} catch (FileNotFoundException e) {//抓取到的是編譯期異常 拋出去的是運(yùn)行期 throw new RuntimeException(e);} finally {System.out.println("不管程序怎樣,這里都將會(huì)被執(zhí)行。");}System.out.println("over");}/*** 我們 當(dāng)前的這個(gè)方法中 有異常 有編譯期異常*/public static void read(String path) throws FileNotFoundException {if (!path.equals("a.txt")) {//如果不是 a.txt這個(gè)文件 // 我假設(shè) 如果不是 a.txt 認(rèn)為 該文件不存在 是一個(gè)錯(cuò)誤 也就是異常 throwthrow new FileNotFoundException("文件不存在");}} }當(dāng)只有在try或者catch中調(diào)用退出JVM的相關(guān)方法,此時(shí)finally才不會(huì)執(zhí)行,否則finally永遠(yuǎn)會(huì)執(zhí)行。
2.5 異常注意事項(xiàng)
-
多個(gè)異常使用捕獲又該如何處理呢?
- 多個(gè)異常分別處理。
- 多個(gè)異常一次捕獲,多次處理。
- 多個(gè)異常一次捕獲一次處理。
一般我們是使用一次捕獲多次處理方式,格式如下:
try{編寫(xiě)可能會(huì)出現(xiàn)異常的代碼 }catch(異常類(lèi)型A e){ 當(dāng)try中出現(xiàn)A類(lèi)型異常,就用該catch來(lái)捕獲.處理異常的代碼//記錄日志/打印異常信息/繼續(xù)拋出異常 }catch(異常類(lèi)型B e){ 當(dāng)try中出現(xiàn)B類(lèi)型異常,就用該catch來(lái)捕獲.處理異常的代碼//記錄日志/打印異常信息/繼續(xù)拋出異常 }注意:這種異常處理方式,要求多個(gè)catch中的異常不能相同,并且若catch中的多個(gè)異常之間有子父類(lèi)異常的關(guān)系,那么子類(lèi)異常要求在上面的catch處理,父類(lèi)異常在下面的catch處理。
-
運(yùn)行時(shí)異常被拋出可以不處理。即不捕獲也不聲明拋出。
-
如果finally有return語(yǔ)句,永遠(yuǎn)返回finally中的結(jié)果,避免該情況.
-
如果父類(lèi)拋出了多個(gè)異常,子類(lèi)重寫(xiě)父類(lèi)方法時(shí),拋出和父類(lèi)相同的異常或者是父類(lèi)異常的子類(lèi)或者不拋出異常。
-
父類(lèi)方法沒(méi)有拋出異常,子類(lèi)重寫(xiě)父類(lèi)該方法時(shí)也不可拋出異常。此時(shí)子類(lèi)產(chǎn)生該異常,只能捕獲處理,不能聲明拋出
第三章 自定義異常
3.1 概述
為什么需要自定義異常類(lèi):
我們說(shuō)了Java中不同的異常類(lèi),分別表示著某一種具體的異常情況,那么在開(kāi)發(fā)中總是有些異常情況是SUN沒(méi)有定義好的,此時(shí)我們根據(jù)自己業(yè)務(wù)的異常情況來(lái)定義異常類(lèi)。例如年齡負(fù)數(shù)問(wèn)題,考試成績(jī)負(fù)數(shù)問(wèn)題等等。
在上述代碼中,發(fā)現(xiàn)這些異常都是JDK內(nèi)部定義好的,但是實(shí)際開(kāi)發(fā)中也會(huì)出現(xiàn)很多異常,這些異常很可能在JDK中沒(méi)有定義過(guò),例如年齡負(fù)數(shù)問(wèn)題,考試成績(jī)負(fù)數(shù)問(wèn)題.那么能不能自己定義異常呢?
什么是自定義異常類(lèi):
在開(kāi)發(fā)中根據(jù)自己業(yè)務(wù)的異常情況來(lái)定義異常類(lèi).
自定義一個(gè)業(yè)務(wù)邏輯異常: RegisterException。一個(gè)注冊(cè)異常類(lèi)。
異常類(lèi)如何定義:
3.2 自定義異常的練習(xí)
要求:我們模擬注冊(cè)操作,如果用戶名已存在,則拋出異常并提示:親,該用戶名已經(jīng)被注冊(cè)。
首先定義一個(gè)登陸異常類(lèi)RegisterException:
// 業(yè)務(wù)邏輯異常 public class RegisterException extends Exception {/*** 空參構(gòu)造*/public RegisterException() {}/**** @param message 表示異常提示*/public RegisterException(String message) {super(message);} }模擬登陸操作,使用數(shù)組模擬數(shù)據(jù)庫(kù)中存儲(chǔ)的數(shù)據(jù),并提供當(dāng)前注冊(cè)賬號(hào)是否存在方法用于判斷。
public class Demo {// 模擬數(shù)據(jù)庫(kù)中已存在賬號(hào)private static String[] names = {"bill","hill","jill"};public static void main(String[] args) { //調(diào)用方法try{// 可能出現(xiàn)異常的代碼checkUsername("nill");System.out.println("注冊(cè)成功");//如果沒(méi)有異常就是注冊(cè)成功}catch(RegisterException e){//處理異常e.printStackTrace();}}//判斷當(dāng)前注冊(cè)賬號(hào)是否存在//因?yàn)槭蔷幾g期異常,又想調(diào)用者去處理 所以聲明該異常public static boolean checkUsername(String uname) throws LoginException{for (String name : names) {if(name.equals(uname)){//如果名字在這里面 就拋出登陸異常throw new RegisterException("親"+name+"已經(jīng)被注冊(cè)了!");}}return true;} }第四章 多線程
我們?cè)谥?#xff0c;學(xué)習(xí)的程序在沒(méi)有跳轉(zhuǎn)語(yǔ)句的前提下,都是由上至下依次執(zhí)行,那現(xiàn)在想要設(shè)計(jì)一個(gè)程序,邊打游戲邊聽(tīng)歌,怎么設(shè)計(jì)?
要解決上述問(wèn)題,咱們得使用多進(jìn)程或者多線程來(lái)解決.
4.1 并發(fā)與并行
- 并發(fā):指兩個(gè)或多個(gè)事件在同一個(gè)時(shí)間段內(nèi)發(fā)生。
- 并行:指兩個(gè)或多個(gè)事件在同一時(shí)刻發(fā)生(同時(shí)發(fā)生)。
在操作系統(tǒng)中,安裝了多個(gè)程序,并發(fā)指的是在一段時(shí)間內(nèi)宏觀上有多個(gè)程序同時(shí)運(yùn)行,這在單 CPU 系統(tǒng)中,每一時(shí)刻只能有一道程序執(zhí)行,即微觀上這些程序是分時(shí)的交替運(yùn)行,只不過(guò)是給人的感覺(jué)是同時(shí)運(yùn)行,那是因?yàn)榉謺r(shí)交替運(yùn)行的時(shí)間是非常短的。
而在多個(gè) CPU 系統(tǒng)中,則這些可以并發(fā)執(zhí)行的程序便可以分配到多個(gè)處理器上(CPU),實(shí)現(xiàn)多任務(wù)并行執(zhí)行,即利用每個(gè)處理器來(lái)處理一個(gè)可以并發(fā)執(zhí)行的程序,這樣多個(gè)程序便可以同時(shí)執(zhí)行。目前電腦市場(chǎng)上說(shuō)的多核 CPU,便是多核處理器,核 越多,并行處理的程序越多,能大大的提高電腦運(yùn)行的效率。
注意:單核處理器的計(jì)算機(jī)肯定是不能并行的處理多個(gè)任務(wù)的,只能是多個(gè)任務(wù)在單個(gè)CPU上并發(fā)運(yùn)行。同理,線程也是一樣的,從宏觀角度上理解線程是并行運(yùn)行的,但是從微觀角度上分析卻是串行運(yùn)行的,即一個(gè)線程一個(gè)線程的去運(yùn)行,當(dāng)系統(tǒng)只有一個(gè)CPU時(shí),線程會(huì)以某種順序執(zhí)行多個(gè)線程,我們把這種情況稱(chēng)之為線程調(diào)度。
4.2 線程與進(jìn)程
-
進(jìn)程:是指一個(gè)內(nèi)存中運(yùn)行的應(yīng)用程序,每個(gè)進(jìn)程都有一個(gè)獨(dú)立的內(nèi)存空間,一個(gè)應(yīng)用程序可以同時(shí)運(yùn)行多個(gè)進(jìn)程;進(jìn)程也是程序的一次執(zhí)行過(guò)程,是系統(tǒng)運(yùn)行程序的基本單位;系統(tǒng)運(yùn)行一個(gè)程序即是一個(gè)進(jìn)程從創(chuàng)建、運(yùn)行到消亡的過(guò)程。
-
線程:線程是進(jìn)程中的一個(gè)執(zhí)行單元,負(fù)責(zé)當(dāng)前進(jìn)程中程序的執(zhí)行,一個(gè)進(jìn)程中至少有一個(gè)線程。一個(gè)進(jìn)程中是可以有多個(gè)線程的,這個(gè)應(yīng)用程序也可以稱(chēng)之為多線程程序。
簡(jiǎn)而言之:一個(gè)程序運(yùn)行后至少有一個(gè)進(jìn)程,一個(gè)進(jìn)程中可以包含多個(gè)線程
我們可以再電腦底部任務(wù)欄,右鍵----->打開(kāi)任務(wù)管理器,可以查看當(dāng)前任務(wù)的進(jìn)程:
進(jìn)程
線程
線程調(diào)度:
-
分時(shí)調(diào)度
所有線程輪流使用 CPU 的使用權(quán),平均分配每個(gè)線程占用 CPU 的時(shí)間。
-
搶占式調(diào)度
優(yōu)先讓優(yōu)先級(jí)高的線程使用 CPU,如果線程的優(yōu)先級(jí)相同,那么會(huì)隨機(jī)選擇一個(gè)(線程隨機(jī)性),Java使用的為搶占式調(diào)度。
- 設(shè)置線程的優(yōu)先級(jí)
- 搶占式調(diào)度詳解
大部分操作系統(tǒng)都支持多進(jìn)程并發(fā)運(yùn)行,現(xiàn)在的操作系統(tǒng)幾乎都支持同時(shí)運(yùn)行多個(gè)程序。比如:現(xiàn)在我們上課一邊使用編輯器,一邊使用錄屏軟件,同時(shí)還開(kāi)著畫(huà)圖板,dos窗口等軟件。此時(shí),這些程序是在同時(shí)運(yùn)行,”感覺(jué)這些軟件好像在同一時(shí)刻運(yùn)行著“。
實(shí)際上,CPU(中央處理器)使用搶占式調(diào)度模式在多個(gè)線程間進(jìn)行著高速的切換。對(duì)于CPU的一個(gè)核而言,某個(gè)時(shí)刻,只能執(zhí)行一個(gè)線程,而 CPU的在多個(gè)線程間切換速度相對(duì)我們的感覺(jué)要快,看上去就是在同一時(shí)刻運(yùn)行。
其實(shí),多線程程序并不能提高程序的運(yùn)行速度,但能夠提高程序運(yùn)行效率,讓CPU的使用率更高。
- 設(shè)置線程的優(yōu)先級(jí)
4.3 創(chuàng)建線程類(lèi)
Java使用java.lang.Thread類(lèi)代表線程,所有的線程對(duì)象都必須是Thread類(lèi)或其子類(lèi)的實(shí)例。每個(gè)線程的作用是完成一定的任務(wù),實(shí)際上就是執(zhí)行一段程序流即一段順序執(zhí)行的代碼。Java使用線程執(zhí)行體來(lái)代表這段程序流。Java中通過(guò)繼承Thread類(lèi)來(lái)創(chuàng)建并啟動(dòng)多線程的步驟如下:
代碼如下:
測(cè)試類(lèi):
public class Demo01 {public static void main(String[] args) {//創(chuàng)建自定義線程對(duì)象MyThread mt = new MyThread("新的線程!");//開(kāi)啟新線程mt.start();//在主方法中執(zhí)行for循環(huán)for (int i = 0; i < 10; i++) {System.out.println("main線程!"+i);}} }自定義線程類(lèi):
public class MyThread extends Thread {//定義指定線程名稱(chēng)的構(gòu)造方法public MyThread(String name) {//調(diào)用父類(lèi)的String參數(shù)的構(gòu)造方法,指定線程的名稱(chēng)super(name);}/*** 重寫(xiě)run方法,完成該線程執(zhí)行的邏輯*/@Overridepublic void run() {for (int i = 0; i < 10; i++) {System.out.println(getName()+":正在執(zhí)行!"+i);}} }總結(jié)
- 上一篇: 计算机网络学习笔记-1.1.5-分层结构
- 下一篇: arp病毒利用的Javascript技术