進(jìn)程和線程的學(xué)習(xí)

并發(fā)
生活中的并發(fā):
在一個(gè)時(shí)間段內(nèi)同時(shí)做好多件事情
例如:人體可以同時(shí)進(jìn)行呼吸,血液循環(huán),思考問題等,在走路的同時(shí)還可以唱歌,等等
計(jì)算機(jī)中的并發(fā):
在使用Eclipse的同時(shí)還可以放音樂,可以同時(shí)運(yùn)行多個(gè)程序。
并發(fā)原理
世間萬(wàn)物都可以同時(shí)完成很多工作,可能生活中是真的并發(fā)存在的,在同一個(gè)時(shí)間段內(nèi)可以同時(shí)做好幾件事情,但是在程序里面,沒有真正意義上的同時(shí)發(fā)生,“同時(shí)”運(yùn)行只是我們感官上的一種表現(xiàn),事實(shí)上線程是并發(fā)運(yùn)行的,OS將時(shí)間劃分為很多片段(時(shí)間片)盡可能均勻的分配給每一個(gè)線程,獲取時(shí)間片段的線程被CPU運(yùn)行,而其他線程全部等待,所以微觀上是走走停停的,宏觀上都在運(yùn)行,這種現(xiàn)象叫做“并發(fā)”,但是絕不是意義上的“同時(shí)發(fā)生”。
只不過CPU在運(yùn)行的時(shí)候太快了,在宏觀上給人的感覺是在一起運(yùn)行,但其實(shí)不是,就像是那個(gè)淘寶客服,如果他打字的速度夠快,那么就可以同時(shí)服務(wù)好幾個(gè)人,CPU也是一樣的,如果有好多個(gè)任務(wù)要處理,他處理的時(shí)候是這個(gè)處理一點(diǎn),那個(gè)處理一點(diǎn),由于太快了,所以宏觀上給人的感覺是同時(shí)處理的,其實(shí)不是.
Java語(yǔ)言提供了并發(fā)機(jī)制,程序員可以在程序中執(zhí)行多個(gè)線程,每一個(gè)線程完成一個(gè)功能,并與其他線程并發(fā)執(zhí)行,這種機(jī)制被稱之為是多線程。
例如我們?cè)谕婺硞€(gè)游戲時(shí),在游戲中我們會(huì)聽到某些背景音樂,某個(gè)角色在移動(dòng),出現(xiàn)某些絢麗的動(dòng)畫效果等,這些在游戲中都是同時(shí)發(fā)生的,但實(shí)際上,播放音樂是在一個(gè)線程中獨(dú)立完成的,移動(dòng)某個(gè)角色,播放某些特效也都是在獨(dú)立的線程中完成的。
什么是進(jìn)程
Windows操作系統(tǒng)是多任務(wù)操作系統(tǒng),以進(jìn)程為單位,一個(gè)進(jìn)程是一個(gè)包含有自身地址的程序,每個(gè)獨(dú)立執(zhí)行的程序都稱之為是進(jìn)程,也就是正在執(zhí)行的程序。系統(tǒng)可以分配給每一個(gè)進(jìn)程一段有限的使用CPU的時(shí)間,也可以稱之為是CPU時(shí)間片,CPU在這段時(shí)間中執(zhí)行某個(gè)進(jìn)程,然后下一個(gè)時(shí)間片又跳到另一個(gè)進(jìn)程中去執(zhí)行,由于CPU轉(zhuǎn)換較快,所以使得每個(gè)進(jìn)程好像是同時(shí)執(zhí)行一樣。
?簡(jiǎn)單來說,進(jìn)程就是程序的執(zhí)行過程。同時(shí),進(jìn)程持有獨(dú)立的資源(獨(dú)立的代碼和數(shù)據(jù)空間)和線程。
進(jìn)程是資源的載體,也就是線程的載體,脫離進(jìn)程去談?wù)摼€程沒有任何的意義
所謂的進(jìn)程就是一個(gè)正在運(yùn)行著的程序
什么是線程
線程是進(jìn)程中的任務(wù)執(zhí)行序列,一個(gè)正在運(yùn)行的程序就是一個(gè)進(jìn)程,那么這個(gè)程序里正在做的事情就是一個(gè)線程.所以線程是進(jìn)程的一部分。
比如:正在運(yùn)行的eclipse是一個(gè)進(jìn)程.而我們通過Eclipse運(yùn)行一個(gè)main方法這就是一個(gè)線程,所以說白了所謂的線程就是一個(gè)正在運(yùn)行的進(jìn)程中的一個(gè)小任務(wù)。
什么是多線程
一個(gè)進(jìn)程中可以同時(shí)包括多個(gè)線程,每個(gè)線程也可以得到一小段程序的執(zhí)行時(shí)間,這樣一個(gè)進(jìn)程就可以具有多個(gè)并發(fā)執(zhí)行的線程。
比如我用百度網(wǎng)盤同時(shí)下載多個(gè)視頻的時(shí)候,每一個(gè)正在下載的視頻,都是一個(gè)線程,線程是進(jìn)程的一部分,一個(gè)進(jìn)程可以包含n個(gè)線程。
一個(gè)進(jìn)程至少有一個(gè)線程。線程的劃分尺度小于進(jìn)程,使得多線程程序的并發(fā)性高。另外,進(jìn)程在執(zhí)行過程中擁有獨(dú)立的內(nèi)存單元,而多個(gè)線程共享內(nèi)存,從而極大地提高了程序的運(yùn)行效率。
線程不能獨(dú)立存在,必須依附于進(jìn)程.
進(jìn)程與線程的區(qū)別
一個(gè)進(jìn)程至少有一個(gè)線程。線程的劃分尺度小于進(jìn)程,使得多線程程序的并發(fā)性高。另外,進(jìn)程在執(zhí)行過程中擁有獨(dú)立的內(nèi)存單元,而多個(gè)線程共享內(nèi)存,從而極大地提高了程序的運(yùn)行效率。
線程在執(zhí)行過程中與進(jìn)程的區(qū)別在于每個(gè)獨(dú)立的線程有一個(gè)程序運(yùn)行的入口、順序執(zhí)行序列和程序的出口。但是線程不能夠獨(dú)立執(zhí)行,必須依存在應(yīng)用程序中,由應(yīng)用程序提供多個(gè)線程執(zhí)行控制。
從邏輯角度來看,多線程的意義在于一個(gè)應(yīng)用程序中,有多個(gè)執(zhí)行部分可以同時(shí)執(zhí)行。但操作系統(tǒng)并沒有將多個(gè)線程看做多個(gè)獨(dú)立的應(yīng)用來實(shí)現(xiàn)進(jìn)程的調(diào)度和管理以及資源分配。
Java中的多線程
Java語(yǔ)言提供了并發(fā)機(jī)制,程序員可以在程序中執(zhí)行多個(gè)線程,每一個(gè)線程完成一個(gè)功能,并與其他線程并發(fā)執(zhí)行,這種機(jī)制被稱之為是多線程。
多線程的意義
多線程的存在,不是提高程序的執(zhí)行速度,其實(shí)是為了提高應(yīng)用程序的使用率。
程序的執(zhí)行其實(shí)就是在搶占CPU的資源
我們不能保證每一個(gè)進(jìn)程或者每一個(gè)線程在每時(shí)每刻搶到,所以線程的執(zhí)行有隨機(jī)性。
Java程序的運(yùn)行原理
java 命令會(huì)啟動(dòng) java 虛擬機(jī),啟動(dòng) JVM,等于啟動(dòng)了一個(gè)應(yīng)用程序,也就是啟動(dòng)了一個(gè)進(jìn)程。
該進(jìn)程會(huì)自動(dòng)啟動(dòng)一個(gè) “主線程” ,然后主線程去調(diào)用某個(gè)類的 main 方法。所以 main方法運(yùn)行在主線程中。
問題:jvm虛擬機(jī)的啟動(dòng)是單線程的還是多線程的?
答:多線程的。
原因是垃圾回收線程也要先啟動(dòng),否則很容易會(huì)出現(xiàn)內(nèi)存溢出。
現(xiàn)在的垃圾回收線程加上前面的主線程,最少啟動(dòng)了兩個(gè)線程,所以,jvm的啟動(dòng)其實(shí)是多線程的。
創(chuàng)建多線程的兩種方式
在Java中主要提供了兩種方式實(shí)現(xiàn)線程
繼承java.lang.Thread類
實(shí)現(xiàn)java.lang.Runnable接口
繼承Thread類創(chuàng)建線程類
Thread類是java.lang包中的線程類,從這個(gè)類中實(shí)例化的對(duì)象代表線程,程序員啟動(dòng)一個(gè)新線程需要?jiǎng)?chuàng)建Thread實(shí)例。
通過繼承Thread類來創(chuàng)建并啟動(dòng)多線程的步驟如下
定義Thread類的子類,并且重寫該類的run()方法,run()方法的方法的方法體就代表了線程需要完成的任務(wù),因此把run()方法稱為線程執(zhí)行體
創(chuàng)建Thread子類的實(shí)例,也就是創(chuàng)建Thread對(duì)象
調(diào)用線程對(duì)象的start()方法來啟動(dòng)該線程


優(yōu)點(diǎn)
使用繼承Thread類創(chuàng)建線程的方式的優(yōu)點(diǎn)在于創(chuàng)建簡(jiǎn)單,適合使用匿名內(nèi)部類形式創(chuàng)建
缺點(diǎn)
繼承沖突,由于Java是單繼承的,這會(huì)導(dǎo)致繼承Thread就無(wú)法再繼承其他類了,這在實(shí)際開發(fā)會(huì)是很不方便的。
重寫run方法相當(dāng)于直接將線程執(zhí)行的任務(wù)寫死在線程中,導(dǎo)致線程與任務(wù)有一個(gè)必然的耦合關(guān)系,不利于線程的重用。
使用Runnable接口創(chuàng)建線程類
為了避免Java單繼承的局限性,所以除了可以繼承Thread類之外還可以實(shí)現(xiàn)于Runnable接口
實(shí)現(xiàn)Runnable接口的程序會(huì)創(chuàng)建一個(gè)Thread對(duì)象,并將Runnable對(duì)象與Thread的對(duì)象相關(guān)聯(lián),Thread類中有以下兩個(gè)構(gòu)造方法
1、public Thread(Runnable target)
2、public Thread(Runnable target,String name)
這兩個(gè)構(gòu)造方法的參數(shù)中都存在Runnable實(shí)例,使用以上構(gòu)造方法就可以將Runnable實(shí)例與Thread類相關(guān)聯(lián)class。
實(shí)現(xiàn)Runnable接口來創(chuàng)建并啟動(dòng)多線程的步驟如下:
定義Runnable接口的實(shí)現(xiàn)類,并重寫該接口的run()方法,該run()方法的方法體同樣是該線程的線程執(zhí)行體
使用參數(shù)為Runnable對(duì)象的構(gòu)造方法創(chuàng)建Thread實(shí)例
調(diào)用start()方法啟動(dòng)線程


說明:在多線程啟動(dòng)的時(shí)候,需要先通過Thread類的構(gòu)造方法Thread(Runnable target)構(gòu)造出對(duì)象,然后調(diào)用Thread對(duì)象的start()方法來運(yùn)行多線程代碼
實(shí)際上所有的多線程代碼都是通過運(yùn)行Thread的start()方法來運(yùn)行的,因此,不管是擴(kuò)展Thread類還是實(shí)現(xiàn)Runnable接口來實(shí)現(xiàn)多線程,最終還是通過Thread對(duì)象的API來控制線程。
使用內(nèi)部類創(chuàng)建線程
通常我們可以通過匿名內(nèi)部類的方式創(chuàng)建線程,使用該方式可以簡(jiǎn)化編寫代碼的復(fù)雜度,當(dāng)一個(gè)線程僅需要一個(gè)實(shí)例時(shí)我們通常使用這種方式來創(chuàng)建。

線程API
Thread.currentThread方法
Thread的靜態(tài)方法currentThread方法可以用于獲取運(yùn)行當(dāng)前代碼片段的線程。
獲取線程信息
Thread提供了 獲取線程信息的相關(guān)方法:
long getId():返回該線程的標(biāo)識(shí)符
String getName():返回該線程的名稱
int getPriority():返回線程的優(yōu)先級(jí)
Thread.state getState():獲取線程的狀態(tài)
boolean isAlive():測(cè)試線程是否處于活動(dòng)狀態(tài)
boolean isDaemon():測(cè)試線程是否為守護(hù)線程
boolean isInterrupted():測(cè)試線程是否已經(jīng)中斷
線程優(yōu)先級(jí)
線程的切換是由線程調(diào)度控制的,我們無(wú)法通過代碼來干涉,但是我們可以通過提高線程的優(yōu)先級(jí)來最大程度的改善線程獲取時(shí)間片的幾率。
線程的優(yōu)先級(jí)被劃分為10級(jí),值分別為1-10,其中1最低,10最高。線程提供了3個(gè)常量來表示最低,最高,以及默認(rèn)優(yōu)先級(jí):
設(shè)置優(yōu)先級(jí)的方法為:
線程的生命周期
當(dāng)線程被創(chuàng)建并啟動(dòng)以后,它既不是一啟動(dòng)就進(jìn)入了執(zhí)行狀態(tài),也不是一直處于執(zhí)行狀態(tài),在線程的生命周期中,它需要經(jīng)過創(chuàng)建(New)、就緒(Runnable)、運(yùn)行(Running)、阻塞(Blocked)和死亡(Dead)這5種狀態(tài),當(dāng)線程啟動(dòng)以后,它不可能一直“霸占”這CPU獨(dú)自運(yùn)行,所以CPU需要在多條線程之間切換,于是線程狀態(tài)也會(huì)在就緒Runnable狀態(tài)和運(yùn)行running階段之間切換。

線程并發(fā)安全
當(dāng)多個(gè)線程的并發(fā)對(duì)同一個(gè)臨界資源操作時(shí),可能由于線程切換時(shí)機(jī)不確定導(dǎo)致程序和設(shè)計(jì)的執(zhí)行方式出現(xiàn)混亂,甚至程序癱瘓.
synchronized關(guān)鍵字
多個(gè)線程并發(fā)讀寫同一個(gè)臨界資源時(shí)候會(huì)發(fā)生"線程并發(fā)安全問題“
常見的臨界資源:
多線程共享實(shí)例變量
多線程共享靜態(tài)公共變量
若想解決線程安全問題,需要將異步的操作變?yōu)橥讲僮鳌?何為同步?那么我們來對(duì)比看一下什么是同步什么異步。
所謂異步操作是指多線程并發(fā)的操作,相當(dāng)于各干各的。
所謂同步操作是指有先后順序的操作,相當(dāng)于你干完我再干。
而java中有一個(gè)關(guān)鍵字名為:synchronized,該關(guān)鍵字是同步鎖,用于將某段代碼變?yōu)橥讲僮鳎瑥亩鉀Q線程并發(fā)安全問題。
