嘉興手機(jī)網(wǎng)站開(kāi)發(fā)費(fèi)用b站2023年免費(fèi)入口
一、概念介紹
什么是線(xiàn)程,什么是進(jìn)程,兩者有什么關(guān)系?
????????進(jìn)程是操作系統(tǒng)資源分配的獨(dú)立單位;而線(xiàn)程是操作系統(tǒng)能夠進(jìn)行調(diào)度和分派的最小單位;線(xiàn)程包含于進(jìn)程之中,是進(jìn)程中的實(shí)際運(yùn)作單位。
例如:
正在運(yùn)行的360安全衛(wèi)士就屬于一個(gè)進(jìn)程
使用360衛(wèi)士中的各個(gè)功能時(shí),就屬于開(kāi)啟一個(gè)線(xiàn)程
1.Thread類(lèi)與Runnable接口
為什么有了Thread類(lèi)還要有Runnable接口,兩者各有什么用途?
????????他們兩個(gè)最主要的區(qū)別:一個(gè)是接口一個(gè)是實(shí)現(xiàn)類(lèi),常用接口可以避免單繼承的局限性外,具體區(qū)別是:繼承Thread類(lèi)的方式可能會(huì)導(dǎo)致類(lèi)的局部變量不能正確的被共享。因?yàn)槊總€(gè)線(xiàn)程都是一個(gè)獨(dú)立的對(duì)象,它們之間不能共享實(shí)例變量,如果需要共享變量,就必須使用靜態(tài)變量或共享對(duì)象鎖。而使用Runnable接口的方式,多個(gè)線(xiàn)程可以共享同一個(gè)Runnable實(shí)例,從而共享實(shí)例變量。
????????使用Runnable接口可以更好的體現(xiàn)面向?qū)ο缶幊痰乃枷?#xff0c;把任務(wù)和線(xiàn)程分離開(kāi)來(lái)。可以把任務(wù)當(dāng)作一個(gè)對(duì)象,而線(xiàn)程可以看作是該對(duì)象(任務(wù))的執(zhí)行者。這樣就可以更好的實(shí)現(xiàn)模塊化設(shè)計(jì),提高代碼的可重用性和可維護(hù)性。
????????使用Runnable接口可以更好地處理多個(gè)線(xiàn)程之間的交互和協(xié)作。因?yàn)閷?shí)現(xiàn)了Runnable接口的實(shí)例可以作為參數(shù)傳遞給Thread類(lèi)的構(gòu)造函數(shù),因此線(xiàn)程(一個(gè)Thread實(shí)例)可以共享同一個(gè)Runnable實(shí)例,并且多個(gè)線(xiàn)程可以同時(shí)執(zhí)行同一個(gè)Runnable實(shí)例的不同方法,從而實(shí)現(xiàn)多個(gè)線(xiàn)程之間的交互和協(xié)作??偟膩?lái)說(shuō),使用Runnable接口的方式更加靈活和通用,可以實(shí)現(xiàn)更多的多線(xiàn)程編程場(chǎng)景,更好的體現(xiàn)面向?qū)ο缶幊痰乃枷?#xff0c;提高代碼的可重用性和可維護(hù)性。
????????但是,使用Thread類(lèi)的方式也有其適用的場(chǎng)景,例如在一些簡(jiǎn)單的多線(xiàn)程編程場(chǎng)景中可以使用繼承Thread類(lèi)的方式來(lái)實(shí)現(xiàn)。
2.并發(fā)和并行的區(qū)別
(1).處理任務(wù)不同
????????并發(fā)(Concurrent)是一個(gè)CPU同時(shí)處理多個(gè)線(xiàn)程任務(wù)。(宏觀上是同時(shí)處理多個(gè)任務(wù),微觀上其實(shí)是CPU在多個(gè)線(xiàn)程之間快速的交替執(zhí)行。操作系統(tǒng)中有一個(gè)組件叫做任務(wù)調(diào)度器,它將CPU的時(shí)間片分配給各個(gè)線(xiàn)程使用,在一個(gè)時(shí)間段的線(xiàn)程運(yùn)行時(shí),其他線(xiàn)程處于掛起狀態(tài),這種就稱(chēng)之為并發(fā)。
????????并行(parallel)是多個(gè)CPU處理器同時(shí)處理多個(gè)線(xiàn)程任務(wù)。(當(dāng)一個(gè)CPU執(zhí)行一個(gè)線(xiàn)程時(shí),另一個(gè)CPU可以執(zhí)行另一個(gè)線(xiàn)程,兩個(gè)線(xiàn)程互不搶占CPU資源,可以同時(shí)進(jìn)行,這就被稱(chēng)之為并行。)
(2).CPU資源不同
????????并發(fā)過(guò)程中,線(xiàn)程之間會(huì)去搶占CPU資源,輪流便用。并行過(guò)程中,線(xiàn)程間不會(huì)搶占CPU資源。(因?yàn)槭嵌鄠€(gè)CPU處理器,各做各的。)
3.什么是線(xiàn)程池,使用線(xiàn)程池有哪些優(yōu)勢(shì)?
? ? ? ? 什么是線(xiàn)程池?
????????線(xiàn)程池,是一種線(xiàn)程使用模式,線(xiàn)程池維護(hù)著多個(gè)線(xiàn)程,等待著管理者為其分配可并發(fā)執(zhí)行的任務(wù),就是可管理、維護(hù)和分配線(xiàn)程的“池子”。
? ? ? ? 為什么使用線(xiàn)程池?
????????為了減少創(chuàng)建和銷(xiāo)毀線(xiàn)程的次數(shù),讓每個(gè)線(xiàn)程郜可以多次的使用;
????????利用線(xiàn)程池可以根據(jù)系統(tǒng)情況調(diào)整線(xiàn)程的數(shù)量,防止消耗過(guò)多內(nèi)存。在實(shí)際使用中,服務(wù)器在創(chuàng)建和銷(xiāo)毀線(xiàn)程上花費(fèi)的時(shí)間和系統(tǒng)資源都相當(dāng)大,使用線(xiàn)程池就可以?xún)?yōu)化這些消耗。
????????通俗的說(shuō):使用線(xiàn)程池就是為了讓線(xiàn)程對(duì)象可以反復(fù)的復(fù)用,不需要每次執(zhí)行任務(wù)時(shí)構(gòu)建一個(gè)新的線(xiàn)程,等到任務(wù)處理完后再銷(xiāo)毀。
(1)使用線(xiàn)程池的優(yōu)勢(shì):
(2)線(xiàn)程池的應(yīng)用場(chǎng)景
二、Java內(nèi)置線(xiàn)程池的使用方法
(一)線(xiàn)程池類(lèi):ThreadPoolExecutor的介紹
????????我們要想自定義線(xiàn)程池,必須先了解線(xiàn)程池的工作原理,才能自己定義線(xiàn)程池 這里我們通過(guò)觀察java中ThreadPoolExecutor的源碼來(lái)學(xué)習(xí)線(xiàn)程池的原理 (源碼演示在idea中查看)
1.ThreadPoolExecutor的構(gòu)造方法(了解這七個(gè)核心參數(shù))
public ThreadPoolExecutor(int corePoolSize, //核心線(xiàn)程數(shù)量int maximumPoolSize, //最大線(xiàn)程數(shù)long keepAliveTime, //最大空閑時(shí)間TimeUnit unit, ? ? ?//時(shí)間單位BlockingQueue<Runnable> workQueue,//任務(wù)隊(duì)列ThreadFactory threadFactory, ? ? ?//線(xiàn)程工廠RejectedExecutionHandler handler //飽和處理機(jī)制)
-
int corePoolSize:核心線(xiàn)程數(shù)量
-
int maximumPoolSize:最大線(xiàn)程數(shù)
-
long keepAliveTime:最大空閑時(shí)間,當(dāng)線(xiàn)程空閑的時(shí)長(zhǎng)達(dá)到該時(shí)間時(shí),會(huì)被自動(dòng)回收。
-
TimeUnit unit:設(shè)置最大空閑時(shí)間的時(shí)間單位
-
BlockingQueue<Runnable>workQueue:任務(wù)隊(duì)列,當(dāng)線(xiàn)程池中所有線(xiàn)程都不空閑時(shí),線(xiàn)程池在收到任務(wù)時(shí),會(huì)在該隊(duì)列中等候;
-
ThreadFactory threadFactory:線(xiàn)程工廠
-
RejectedExecutionHandler handler:飽和處理機(jī)制,當(dāng)線(xiàn)程池中的線(xiàn)程已達(dá)到最大線(xiàn)程數(shù)量,且都在工作;并且任務(wù)隊(duì)列上也已經(jīng)排滿(mǎn)等候的任務(wù)時(shí),證明當(dāng)前線(xiàn)程池已經(jīng)飽和,此時(shí)再來(lái)任務(wù)將會(huì)觸發(fā)該機(jī)制。
2.線(xiàn)程池的工作流程
我們通過(guò)下面一個(gè)場(chǎng)景來(lái)理解ThreadPoolExecutor中的各個(gè)參數(shù),以及線(xiàn)程池的工作流程:
????????a客戶(hù)(任務(wù))去銀行(線(xiàn)程池)辦理業(yè)務(wù),但銀行剛開(kāi)始營(yíng)業(yè),窗口服務(wù)員還未就位(相當(dāng)于線(xiàn)程池中初始線(xiàn)程數(shù)量為0),于是經(jīng)理(線(xiàn)程池管理者)就安排1號(hào)工作人員(創(chuàng)建1號(hào)線(xiàn)程執(zhí)行任務(wù))接待a客戶(hù)(創(chuàng)建線(xiàn)程);
????????在a客戶(hù)業(yè)務(wù)還沒(méi)辦完時(shí),b客戶(hù)(任務(wù))又來(lái)了,于是經(jīng)理(線(xiàn)程池管理者)就安排2號(hào)工作人員(創(chuàng)建2號(hào)線(xiàn)程執(zhí)行任務(wù))接待b客戶(hù)(又創(chuàng)建了一個(gè)新的線(xiàn)程) 假設(shè)該銀行總共就2個(gè)窗口(核心線(xiàn)程數(shù)量是2);
????????緊接著在a,b客戶(hù)都沒(méi)有結(jié)束的情況下客戶(hù)來(lái)了,于是經(jīng)理(線(xiàn)程池管理者)就安排c客戶(hù)先坐到銀行大廳的座位上(空位相當(dāng)于是任務(wù)隊(duì)列)等候,并告知他: 如果1、2號(hào)工作人員空出,c就可以前去辦理業(yè)務(wù);
????????此時(shí)d客戶(hù)又到了銀行,(工作人員都在忙,大廳座位也滿(mǎn)了)于是經(jīng)理趕緊安排臨時(shí)工(新創(chuàng)建一個(gè)線(xiàn)程)在大堂站著,手持pad設(shè)備給d客戶(hù)辦理業(yè)務(wù);
????????假如前面的業(yè)務(wù)都沒(méi)有結(jié)束的時(shí)候e客戶(hù)又來(lái)了,此時(shí)正式工作人員都上了,臨時(shí)工也上了,座位也滿(mǎn)了(臨時(shí)工加正式員工的總數(shù)量就是最大線(xiàn)程數(shù)),于是經(jīng)理只能按《超出銀行最大接待能力處理辦法》(飽和處理機(jī)制)拒接接待e客戶(hù);
????????最后,進(jìn)來(lái)辦業(yè)務(wù)的人少了,大廳的臨時(shí)工空閑時(shí)間也超過(guò)了1個(gè)小時(shí)(最大空閑時(shí)間),經(jīng)理就會(huì)讓這部分空閑的臨時(shí)員工下班。(銷(xiāo)毀線(xiàn)程)
????????但是為了保證銀行正常工作(有一個(gè)alowCoreThreadTimeout變量控制是否允許銷(xiāo)毀核心線(xiàn)程,默認(rèn)false),即使正式員工閑著,也不得提前下班,所以1、2號(hào)工作人員繼續(xù)待著(池內(nèi)保持核心線(xiàn)程數(shù)量);
3. 線(xiàn)程池的4個(gè)參數(shù)的設(shè)計(jì):
(1)核心線(xiàn)程數(shù)(corePoolSize)
核心線(xiàn)程數(shù)的設(shè)計(jì)需要依據(jù)任務(wù)的處理時(shí)間和每秒產(chǎn)生的任務(wù)數(shù)量來(lái)確定,例如:
執(zhí)行一個(gè)任務(wù)需要0.1秒,系統(tǒng)百分之80的時(shí)間每秒都會(huì)產(chǎn)生100個(gè)任務(wù),那么要想在1秒內(nèi)處理完這100個(gè)任務(wù),就需要10個(gè)線(xiàn)程,此時(shí)我們就可以設(shè)計(jì)核心線(xiàn)程數(shù)為10;當(dāng)然實(shí)際情況不可能這么平均,所以我們一般按照8020原則設(shè)計(jì)即可,既按照百分之80的情況設(shè)計(jì)核心線(xiàn)程數(shù),剩下的百分之20可以利用最大線(xiàn)程數(shù)處理。
(2)任務(wù)隊(duì)列長(zhǎng)度(workQueue)
任務(wù)隊(duì)列長(zhǎng)度一般設(shè)計(jì)為:核心線(xiàn)程數(shù)/單個(gè)任務(wù)執(zhí)行時(shí)間*2即可;例如上面的場(chǎng)景中,核心線(xiàn)程數(shù)設(shè)計(jì)為10,單個(gè)任務(wù)執(zhí)行時(shí)間為 0.1秒,則隊(duì)列長(zhǎng)度可以設(shè)計(jì)為200。
(3)最大線(xiàn)程數(shù)(maximumPoolSize)
最大線(xiàn)程數(shù)的設(shè)計(jì)除了需要參照核心線(xiàn)程數(shù)的條件外,還需要參照系統(tǒng)每秒產(chǎn)生的最大任務(wù)數(shù)決定:例如:上述環(huán)境中,如果系統(tǒng)每秒最大產(chǎn)生的任務(wù)是1000個(gè)。那么,最大線(xiàn)程數(shù)=(最大任務(wù)數(shù)-任務(wù)隊(duì)列長(zhǎng)度)單個(gè)任務(wù)執(zhí)行時(shí)間;既:最大線(xiàn)程數(shù)=(1000-200)0.1=80個(gè)。
(4)最大空閑時(shí)間(keepAliveTime)
這個(gè)參數(shù)的設(shè)計(jì)完全參考系統(tǒng)運(yùn)行環(huán)境和硬件壓力設(shè)定,沒(méi)有固定的參考值,用戶(hù)可以根據(jù)經(jīng)驗(yàn)和系統(tǒng)產(chǎn)生任務(wù)的時(shí)間間隔合理設(shè)置一個(gè)值即可。
注意:上面4個(gè)參數(shù)的設(shè)置只是一般的設(shè)計(jì)原則,并不是固定的,用戶(hù)也可以根據(jù)實(shí)際情況靈活調(diào)整!
4.線(xiàn)程池類(lèi):ThreadPoolExecutor的實(shí)際使用
1.自定義線(xiàn)程池-實(shí)現(xiàn)步驟
-
(1)編寫(xiě)任務(wù)類(lèi)(MyTask),實(shí)現(xiàn)Runnable接口;
-
(2)編寫(xiě)線(xiàn)程類(lèi)(MyWorker),用于執(zhí)行任務(wù),需要持有所有任務(wù):
-
(3)編寫(xiě)線(xiàn)程池類(lèi)(MyThreadPool),包含提交任務(wù),執(zhí)行任務(wù)的能力;
-
(4)編寫(xiě)測(cè)試類(lèi)(MyTest),創(chuàng)建線(xiàn)程池對(duì)象,提交多個(gè)任務(wù)測(cè)試; (具體代碼參考idea)
小提示:關(guān)于線(xiàn)程池的功能比較繁多,這里僅僅模擬了核心功能,其他功能大家可以自行考補(bǔ)全;