您好,歡迎來(lái)到賦能網(wǎng)!

Java多線(xiàn)程的知識(shí)學(xué)習(xí)

賦能網(wǎng) 2023-05-10 57


進(jìn)程和線(xiàn)程的區(qū)別:

      進(jìn)程:每個(gè)進(jìn)程都有獨(dú)立的代碼和數(shù)據(jù)空間(進(jìn)程上下文),進(jìn)程間的切換會(huì)有較大的開(kāi)銷(xiāo),一個(gè)進(jìn)程包含1--n個(gè)線(xiàn)程。

      線(xiàn)程:同一類(lèi)線(xiàn)程共享代碼和數(shù)據(jù)空間,每個(gè)線(xiàn)程有獨(dú)立的運(yùn)行棧和程序計(jì)數(shù)器(PC),線(xiàn)程切換開(kāi)銷(xiāo)小。

      多進(jìn)程是指操作系統(tǒng)能同時(shí)運(yùn)行多個(gè)任務(wù)(程序);多線(xiàn)程是指在同一程序中有多個(gè)順序流在執(zhí)行。

      線(xiàn)程和進(jìn)程一樣分為五個(gè)階段:創(chuàng)建、就緒、運(yùn)行、阻塞、終止。

      在java中要想實(shí)現(xiàn)多線(xiàn)程,有兩種手段,一種是繼續(xù)Thread類(lèi),另外一種是實(shí)現(xiàn)Runable接口。

一、擴(kuò)展java.lang.Thread類(lèi)

      程序啟動(dòng)運(yùn)行main時(shí)候,java虛擬機(jī)啟動(dòng)一個(gè)進(jìn)程,主線(xiàn)程main在main()調(diào)用時(shí)候被創(chuàng)建。隨著調(diào)用其他對(duì)象的start方法,另外的線(xiàn)程也啟動(dòng)了,這樣,整個(gè)應(yīng)用就在多線(xiàn)程下運(yùn)行。

      注意:start()方法的調(diào)用后并不是立即執(zhí)行多線(xiàn)程代碼,而是使得該線(xiàn)程變?yōu)榭蛇\(yùn)行態(tài)(Runnable),什么時(shí)候運(yùn)行是由操作系統(tǒng)決定的。

      從程序運(yùn)行的結(jié)果可以發(fā)現(xiàn),多線(xiàn)程程序是亂序執(zhí)行。因此,只有亂序執(zhí)行的代碼才有必要設(shè)計(jì)為多線(xiàn)程。

      Thread.sleep()方法調(diào)用目的是不讓當(dāng)前線(xiàn)程獨(dú)自霸占該進(jìn)程所獲取的CPU資源,以留出一定時(shí)間給其他線(xiàn)程執(zhí)行的機(jī)會(huì)。

      實(shí)際上所有的多線(xiàn)程代碼執(zhí)行順序都是不確定的,每次執(zhí)行的結(jié)果都是隨機(jī)的。但是start方法重復(fù)調(diào)用的話(huà),會(huì)出現(xiàn)java.lang.IllegalThreadStateException異常。

二、實(shí)現(xiàn)java.lang.Runnable接口

      通過(guò)實(shí)現(xiàn)Runnable接口,使得類(lèi)有了多線(xiàn)程類(lèi)的特征。run()方法是多線(xiàn)程程序的一個(gè)約定。所有的多線(xiàn)程代碼都在run方法里面。Thread類(lèi)實(shí)際上也是實(shí)現(xiàn)了Runnable接口的類(lèi)。

      在啟動(dòng)的多線(xiàn)程的時(shí)候,需要先通過(guò)Thread類(lèi)的構(gòu)造方法Thread(Runnable target) 構(gòu)造出對(duì)象,然后調(diào)用Thread對(duì)象的start()方法來(lái)運(yùn)行多線(xiàn)程代碼。

      實(shí)際上所有的多線(xiàn)程代碼都是通過(guò)運(yùn)行Thread的start()方法來(lái)運(yùn)行的。因此,不管是擴(kuò)展Thread類(lèi)還是實(shí)現(xiàn)Runnable接口來(lái)實(shí)現(xiàn)多線(xiàn)程,最終還是通過(guò)Thread的對(duì)象的API來(lái)控制線(xiàn)程的,熟悉Thread類(lèi)的API是進(jìn)行多線(xiàn)程編程的基礎(chǔ)。

三、Thread和Runnable的區(qū)別

      實(shí)現(xiàn)Runnable接口比繼承Thread類(lèi)所具有的優(yōu)勢(shì):

      1)適合多個(gè)相同的程序代碼的線(xiàn)程去處理同一個(gè)資源;

      2)可以避免java中的單繼承的限制;

      3)增加程序的健壯性,代碼可以被多個(gè)線(xiàn)程共享,代碼和數(shù)據(jù)獨(dú)立。

四、線(xiàn)程狀態(tài)轉(zhuǎn)換

      1、新建狀態(tài)(New):新創(chuàng)建了一個(gè)線(xiàn)程對(duì)象。

      2、就緒狀態(tài)(Runnable):線(xiàn)程對(duì)象創(chuàng)建后,其他線(xiàn)程調(diào)用了該對(duì)象的start()方法。該狀態(tài)的線(xiàn)程位于可運(yùn)行線(xiàn)程池中,變得可運(yùn)行,等待獲取CPU的使用權(quán)。

      3、運(yùn)行狀態(tài)(Running):就緒狀態(tài)的線(xiàn)程獲取了CPU,執(zhí)行程序代碼。

      4、阻塞狀態(tài)(Blocked):阻塞狀態(tài)是線(xiàn)程因?yàn)槟撤N原因放棄CPU使用權(quán),暫時(shí)停止運(yùn)行。直到線(xiàn)程進(jìn)入就緒狀態(tài),才有機(jī)會(huì)轉(zhuǎn)到運(yùn)行狀態(tài)。阻塞的情況分三種:

      1》等待阻塞:運(yùn)行的線(xiàn)程執(zhí)行wait()方法,JVM會(huì)把該線(xiàn)程放入等待池中。

      2》同步阻塞:運(yùn)行的線(xiàn)程在獲取對(duì)象的同步鎖時(shí),若該同步鎖被別的線(xiàn)程占用,則JVM會(huì)把該線(xiàn)程放入鎖池中。

      3》其他阻塞:運(yùn)行的線(xiàn)程執(zhí)行sleep()或join()方法,或者發(fā)出了I/O請(qǐng)求時(shí),JVM會(huì)把該線(xiàn)程置為阻塞狀態(tài)。當(dāng)sleep()狀態(tài)超時(shí)、join()等待線(xiàn)程終止或者超時(shí)、或者I/O處理完畢時(shí),線(xiàn)程重新轉(zhuǎn)入就緒狀態(tài)。

      5、死亡狀態(tài)(Dead):線(xiàn)程執(zhí)行完了或者因異常退出了run()方法,該線(xiàn)程結(jié)束生命周期。

五、線(xiàn)程調(diào)度

1、調(diào)整線(xiàn)程優(yōu)先級(jí):Java線(xiàn)程有優(yōu)先級(jí),優(yōu)先級(jí)高的線(xiàn)程會(huì)獲得較多的運(yùn)行機(jī)會(huì)。 

      Java線(xiàn)程的優(yōu)先級(jí)用整數(shù)表示,取值范圍是1~10,Thread類(lèi)有以下三個(gè)靜態(tài)常量:

      static int MAX_PRIORITY、線(xiàn)程可以具有的最高優(yōu)先級(jí),取值為10。

      static int MIN_PRIORITY、線(xiàn)程可以具有的最低優(yōu)先級(jí),取值為1。

      static int NORM_PRIORITY、分配給線(xiàn)程的默認(rèn)優(yōu)先級(jí),取值為5。 

       Thread類(lèi)的setPriority()和getPriority()方法分別用來(lái)設(shè)置和獲取線(xiàn)程的優(yōu)先級(jí)。

      每個(gè)線(xiàn)程都有默認(rèn)的優(yōu)先級(jí)。主線(xiàn)程的默認(rèn)優(yōu)先級(jí)為T(mén)hread.NORM_PRIORITY。

      線(xiàn)程的優(yōu)先級(jí)有繼承關(guān)系,比如A線(xiàn)程中創(chuàng)建了B線(xiàn)程,那么B將和A具有相同的優(yōu)先級(jí)。

      JVM提供了10個(gè)線(xiàn)程優(yōu)先級(jí),但與常見(jiàn)的操作系統(tǒng)都不能很好的映射。如果希望程序能移植到各個(gè)操作系統(tǒng)中,應(yīng)該僅僅使用Thread類(lèi)有以下三個(gè)靜態(tài)常量作為優(yōu)先級(jí),這樣能保證同樣的優(yōu)先級(jí)采用了同樣的調(diào)度方式。

2、線(xiàn)程睡眠:

      Thread.sleep(long millis)方法,使線(xiàn)程轉(zhuǎn)到阻塞狀態(tài)。millis參數(shù)設(shè)定睡眠的時(shí)間,以毫秒為單位。當(dāng)睡眠結(jié)束后,就轉(zhuǎn)為就緒(Runnable)狀態(tài)。sleep()平臺(tái)移植性好。 

3、線(xiàn)程等待:

      Object類(lèi)中的wait()方法,導(dǎo)致當(dāng)前的線(xiàn)程等待,直到其他線(xiàn)程調(diào)用此對(duì)象的 notify() 方法或 notifyAll() 喚醒方法。這個(gè)兩個(gè)喚醒方法也是Object類(lèi)中的方法,行為等價(jià)于調(diào)用 wait(0) 一樣。

4、線(xiàn)程讓步:

      Thread.yield() 方法,暫停當(dāng)前正在執(zhí)行的線(xiàn)程對(duì)象,把執(zhí)行機(jī)會(huì)讓給相同或者更高優(yōu)先級(jí)的線(xiàn)程。

5、線(xiàn)程加入:

      join()方法,等待其他線(xiàn)程終止。在當(dāng)前線(xiàn)程中調(diào)用另一個(gè)線(xiàn)程的join()方法,則當(dāng)前線(xiàn)程轉(zhuǎn)入阻塞狀態(tài),直到另一個(gè)進(jìn)程運(yùn)行結(jié)束,當(dāng)前線(xiàn)程再由阻塞轉(zhuǎn)為就緒狀態(tài)。

6、線(xiàn)程喚醒:

      Object類(lèi)中的notify()方法,喚醒在此對(duì)象監(jiān)視器上等待的單個(gè)線(xiàn)程。如果所有線(xiàn)程都在此對(duì)象上等待,則會(huì)選擇喚醒其中一個(gè)線(xiàn)程。選擇是任意性的,并在對(duì)實(shí)現(xiàn)做出決定時(shí)發(fā)生。線(xiàn)程通過(guò)調(diào)用其中一個(gè) wait 方法,在對(duì)象的監(jiān)視器上等待。 直到當(dāng)前的線(xiàn)程放棄此對(duì)象上的鎖定,才能繼續(xù)執(zhí)行被喚醒的線(xiàn)程。被喚醒的線(xiàn)程將以常規(guī)方式與在該對(duì)象上主動(dòng)同步的其他所有線(xiàn)程進(jìn)行競(jìng)爭(zhēng);例如,喚醒的線(xiàn)程在作為鎖定此對(duì)象的下一個(gè)線(xiàn)程方面沒(méi)有可靠的特權(quán)或劣勢(shì)。類(lèi)似的方法還有一個(gè)notifyAll(),喚醒在此對(duì)象監(jiān)視器上等待的所有線(xiàn)程。

六、線(xiàn)程同步

      1、synchronized關(guān)鍵字的作用域有二種:

      一種是某個(gè)對(duì)象實(shí)例內(nèi),synchronized aMethod(){}可以防止多個(gè)線(xiàn)程同時(shí)訪問(wèn)這個(gè)對(duì)象的synchronized方法(如果一個(gè)對(duì)象有多個(gè)synchronized方法,只要一個(gè)線(xiàn)程訪問(wèn)了其中的一個(gè)synchronized方法,其它線(xiàn)程不能同時(shí)訪問(wèn)這個(gè)對(duì)象中任何一個(gè)synchronized方法)。這時(shí),不同的對(duì)象實(shí)例的synchronized方法是不相干擾的。也就是說(shuō),其它線(xiàn)程照樣可以同時(shí)訪問(wèn)相同類(lèi)的另一個(gè)對(duì)象實(shí)例中的synchronized方法;

      第二種是某個(gè)類(lèi)的范圍,synchronized static aStaticMethod{}防止多個(gè)線(xiàn)程同時(shí)訪問(wèn)這個(gè)類(lèi)中的synchronized static 方法。它可以對(duì)類(lèi)的所有對(duì)象實(shí)例起作用。

      2、除了方法前用synchronized關(guān)鍵字,synchronized關(guān)鍵字還可以用于方法中的某個(gè)區(qū)塊中,表示只對(duì)這個(gè)區(qū)塊的資源實(shí)行互斥訪問(wèn)。用法是: synchronized(this){},它的作用域是當(dāng)前對(duì)象;

      3、synchronized關(guān)鍵字是不能繼承的,也就是說(shuō),基類(lèi)的方法synchronized f(){} 在繼承類(lèi)中并不自動(dòng)是synchronized f(){},而是變成了f(){}。繼承類(lèi)需要你顯式的指定它的某個(gè)方法為synchronized方法。

  想了解更多相關(guān)資訊請(qǐng)關(guān)注java培訓(xùn)頻道-查看更多,了解相關(guān)專(zhuān)業(yè)課程信息您可在線(xiàn)咨詢(xún)也可免費(fèi)申請(qǐng)?jiān)囌n。關(guān)注賦能網(wǎng)了解更多:4008-569-579

本文鏈接:

本文章“Java多線(xiàn)程的知識(shí)學(xué)習(xí)”已幫助 57 人

免責(zé)聲明:本信息由用戶(hù)發(fā)布,本站不承擔(dān)本信息引起的任何交易及知識(shí)產(chǎn)權(quán)侵權(quán)的法律責(zé)任!

本文由賦能網(wǎng) 整理發(fā)布。了解更多培訓(xùn)機(jī)構(gòu)》培訓(xùn)課程》學(xué)習(xí)資訊》課程優(yōu)惠》課程開(kāi)班》學(xué)校地址等機(jī)構(gòu)信息,可以留下您的聯(lián)系方式,讓課程老師跟你詳細(xì)解答:
咨詢(xún)熱線(xiàn):4008-569-579

如果本頁(yè)不是您要找的課程,您也可以百度查找一下: