是一個(gè)具有一定獨(dú)立功能的程序在一個(gè)數(shù)據(jù)集上的一次動(dòng)態(tài)執(zhí)行的過(guò)程,是操作系統(tǒng)進(jìn)行資源分配和調(diào)度的一個(gè)獨(dú)立單位,是應(yīng)用程序運(yùn)行的載體。
成都創(chuàng)新互聯(lián)專注于江口網(wǎng)站建設(shè)服務(wù)及定制,我們擁有豐富的企業(yè)做網(wǎng)站經(jīng)驗(yàn)。 熱誠(chéng)為您提供江口營(yíng)銷型網(wǎng)站建設(shè),江口網(wǎng)站制作、江口網(wǎng)頁(yè)設(shè)計(jì)、江口網(wǎng)站官網(wǎng)定制、重慶小程序開(kāi)發(fā)服務(wù),打造江口網(wǎng)絡(luò)公司原創(chuàng)品牌,更為您提供江口網(wǎng)站排名全網(wǎng)營(yíng)銷落地服務(wù)。
線程是操作系統(tǒng)能夠進(jìn)行運(yùn)算調(diào)度的最小單位。
它被包含在進(jìn)程之中,是進(jìn)程中的實(shí)際運(yùn)作單位。
一條線程指的是進(jìn)程中一個(gè)單一順序的控制流,一個(gè)進(jìn)程中可以并發(fā)多個(gè)線程,每條線程并行執(zhí)行不同的任務(wù)。
進(jìn)程和線程的主要差別在于它們是不同的操作系統(tǒng)資源管理方式。
進(jìn)程有獨(dú)立的地址空間,一個(gè)進(jìn)程崩潰后,在保護(hù)模式下不會(huì)對(duì)其它進(jìn)程產(chǎn)生影響。
線程只是一個(gè)進(jìn)程中的不同執(zhí)行路徑。線程有自己的堆棧和局部變量,但線程之間沒(méi)有單獨(dú)的地址空間,一個(gè)線程死掉就等于整個(gè)進(jìn)程死掉,所以多進(jìn)程的程序要比多線程的程序健壯,但在進(jìn)程切換時(shí),耗費(fèi)資源較大,效率要差一些。
但對(duì)于一些要求同時(shí)進(jìn)行并且又要共享某些變量的并發(fā)操作,只能用線程,不能用進(jìn)程。
單線程程序:程序執(zhí)行過(guò)程中只有一個(gè)有效操作的序列,不同操作之間都有明確的執(zhí)行先后順序,容易出現(xiàn)代碼阻塞
多線程程序:有多個(gè)線程,線程間獨(dú)立運(yùn)行,能有效地避免代碼阻塞,并且提高程序的運(yùn)行性能
(1)使用多線程可以減少程序的響應(yīng)時(shí)間。 在單線程的情況下,如果某個(gè)程序很耗時(shí)或者陷入長(zhǎng)時(shí)間等待(如等待網(wǎng)絡(luò)響應(yīng)),此時(shí)程序?qū)⒉粫?huì)相應(yīng)鼠標(biāo)和鍵盤等操作,使用多線程后,可以把這個(gè)耗時(shí)的線程分配到一個(gè)單獨(dú)的線程去執(zhí)行,從而是程序具備了更好的交互性。
(2)與進(jìn)程相比,線程的創(chuàng)建和切換開(kāi)銷更小。 由于啟動(dòng)一個(gè)新的線程必須給這個(gè)線程分配獨(dú)立的地址空間,建立許多數(shù)據(jù)結(jié)構(gòu)來(lái)維護(hù)線程代碼段、數(shù)據(jù)段等信息,而運(yùn)行于同一個(gè)進(jìn)程內(nèi)的線程共享代碼段、數(shù)據(jù)段,線程的啟動(dòng)或切換的開(kāi)銷就比進(jìn)程要少很多。同時(shí)多線程在數(shù)據(jù)共享方面效率非常高。
(3)多CPU或多核心計(jì)算機(jī)本身就具有執(zhí)行多線程的能力。 如果使用單個(gè)線程,將無(wú)法重復(fù)利用計(jì)算機(jī)資源,造成資源的巨大浪費(fèi)。因此在多CPU計(jì)算機(jī)上使用多線程能提高CPU的利用率。
(4)使用多線程能簡(jiǎn)化程序的結(jié)構(gòu),使用程序便于理解和維護(hù)。 一個(gè)非常復(fù)雜的進(jìn)程可以分成多個(gè)線程來(lái)執(zhí)行。
當(dāng)多個(gè)線程訪問(wèn)同一個(gè)對(duì)象時(shí),如果不用考慮這些線程在運(yùn)行時(shí)環(huán)境下的調(diào)度和交替運(yùn)行,也不需要進(jìn)行額外的同步,或者在調(diào)用方進(jìn)行任何其他的協(xié)調(diào)操作,調(diào)用這個(gè)對(duì)象的行為都可以獲取正確的結(jié)果,那這個(gè)對(duì)象是線程安全的。 ——<<深入Java虛擬機(jī)>>
Java允許多線程并發(fā)控制,當(dāng)多個(gè)線程同時(shí)操作一個(gè)可共享的資源變量時(shí)(如數(shù)據(jù)的增刪改查),將會(huì)導(dǎo)致數(shù)據(jù)不準(zhǔn)確,相互之間產(chǎn)生沖突。
因此加入同步鎖以避免在該線程沒(méi)有完成操作之前,被其他線程的調(diào)用,從而保證了該變量的唯一性和準(zhǔn)確性。
對(duì)非安全的代碼進(jìn)行加鎖控制
使用線程安全的類
多線程并發(fā)情況下,線程共享的變量改為方法級(jí)的局部變量
檢查數(shù)值、改變數(shù)值,以及可能發(fā)生的睡眠操作均作為單一的、不可分割的原子操作完成。
Java中所有變量都儲(chǔ)存在主存中,對(duì)于所有線程都是共享的(因?yàn)樵谕贿M(jìn)程中),每個(gè)線程都有自己的工作內(nèi)存或本地內(nèi)存(Working Memory),工作內(nèi)存中保存的是主存中某些變量的拷貝,線程對(duì)所有變量的操作都是在工作內(nèi)存中進(jìn)行,而線程之間無(wú)法相互直接訪問(wèn),變量傳遞均需要通過(guò)主存完成,但是在程序內(nèi)部可以互相調(diào)用(通過(guò)對(duì)象方法),所有線程間的通信相對(duì)簡(jiǎn)單,速度也很快。?
2、進(jìn)程間的內(nèi)部數(shù)據(jù)和狀態(tài)都是相互完全獨(dú)立的,因此進(jìn)程間通信大多數(shù)情況是必須通過(guò)網(wǎng)絡(luò)實(shí)現(xiàn)。線程本身的數(shù)據(jù),通常只有寄存器數(shù)據(jù),以及一個(gè)程序執(zhí)行時(shí)使用的堆棧,所以線程的切換比進(jìn)程切換的負(fù)擔(dān)要小。
3、CPU對(duì)于各個(gè)線程的調(diào)度是隨機(jī)的(分時(shí)調(diào)度),在Java程序中,JVM負(fù)責(zé)線程的調(diào)度。 線程調(diào)度是指按照特定的機(jī)制為多個(gè)線程分配CPU的使用權(quán),也就是實(shí)際執(zhí)行的時(shí)候是線程,因此CPU調(diào)度的最小單位是線程,而資源分配的最小單位是進(jìn)程。
棧:在函數(shù)中定義的基本類型的變量和對(duì)象的引用變量都是在函數(shù)的棧內(nèi)存中分配。
堆:堆內(nèi)存用于存放由new創(chuàng)建的對(duì)象和數(shù)組。
從通俗化的角度來(lái)說(shuō),堆是用來(lái)存放對(duì)象的,棧是用來(lái)存放執(zhí)行程序的
-Xss參數(shù)用來(lái)控制線程的堆棧大小。
當(dāng)兩個(gè)線程競(jìng)爭(zhēng)同一資源時(shí),如果對(duì)資源的訪問(wèn)順序敏感,就稱存在競(jìng)態(tài)條件。
在臨界區(qū)中使用適當(dāng)?shù)耐骄涂梢员苊飧?jìng)態(tài)條件。
界區(qū)實(shí)現(xiàn)方法有兩種,一種是用synchronized,一種是用Lock顯式鎖實(shí)現(xiàn)。
不可變的對(duì)象一定是線程安全的,并且永遠(yuǎn)也不需要額外的同步。
Java類庫(kù)中大多數(shù)基本數(shù)值類如Integer、String和BigInteger都是不可變的。
由類的規(guī)格說(shuō)明所規(guī)定的約束在對(duì)象被多個(gè)線程訪問(wèn)時(shí)仍然有效,不管運(yùn)行時(shí)環(huán)境如何排列,線程都不需要任何額外的同步。
如 Random 、ConcurrentHashMap、Concurrent集合、atomic
有條件的線程安全類對(duì)于單獨(dú)的操作可以是線程安全的,但是某些操作序列可能需要外部同步。
有條件線程安全的最常見(jiàn)的例子是遍歷由 Hashtable 或者 Vector 或者返回的迭代器
線程兼容類不是線程安全的,但是可以通過(guò)正確使用同步而在并發(fā)環(huán)境中安全地使用。
如ArrayList HashMap
線程對(duì)立是那些不管是否采用了同步措施,都不能在多線程環(huán)境中并發(fā)使用的代碼。
如如System.setOut()、System.runFinalizersOnExit()
每一個(gè)線程都是有優(yōu)先級(jí)的,一般來(lái)說(shuō),高優(yōu)先級(jí)的線程在運(yùn)行時(shí)會(huì)具有優(yōu)先權(quán),但這依賴于線程調(diào)度的實(shí)現(xiàn),這個(gè)實(shí)現(xiàn)是和操作系統(tǒng)相關(guān)的(OSdependent)。
可以定義線程的優(yōu)先級(jí),但是這并不能保證高優(yōu)先級(jí)的線程會(huì)在低優(yōu)先級(jí)的線程前執(zhí)行。線程優(yōu)先級(jí)是一個(gè)int變量(從1-10),1代表最低優(yōu)先級(jí),10代表最高優(yōu)先級(jí)。
線程調(diào)度器是一個(gè)操作系統(tǒng)服務(wù),它負(fù)責(zé)為Runnable狀態(tài)的線程分配CPU時(shí)間。一旦創(chuàng)建一個(gè)線程并啟動(dòng)它,它的執(zhí)行便依賴于線程調(diào)度器的實(shí)現(xiàn)。
時(shí)間分片是指將可用的CPU時(shí)間分配給可用的Runnable線程的過(guò)程。分配CPU時(shí)間可以基于線程優(yōu)先級(jí)或者線程等待的時(shí)間。
線程調(diào)度并不受到Java虛擬機(jī)控制,所以由應(yīng)用程序來(lái)控制它是更好的選擇。
單核CPU也支持多線程執(zhí)行代碼,CPU通過(guò)給每個(gè)線程分配CPU時(shí)間片來(lái)實(shí)現(xiàn)這個(gè)機(jī)制。時(shí)間片是CPU分配給各個(gè)線程的時(shí)間,因?yàn)闀r(shí)間片非常短,所以CPU通過(guò)不停地切換線程執(zhí)行,讓我們感覺(jué)多個(gè)線程時(shí)同時(shí)執(zhí)行的,時(shí)間片一般是幾十毫秒(ms)。
操作系統(tǒng)中,CPU時(shí)間分片切換到另一個(gè)就緒的線程,則需要保存當(dāng)前線程的運(yùn)行的位置,同時(shí)需要加載需要恢復(fù)線程的環(huán)境信息。
守護(hù)線程都是為JVM中所有非守護(hù)線程的運(yùn)行提供便利服務(wù): 只要當(dāng)前JVM實(shí)例中尚存在任何一個(gè)非守護(hù)線程沒(méi)有結(jié)束,守護(hù)線程就全部工作;只有當(dāng)最后一個(gè)非守護(hù)線程結(jié)束時(shí),守護(hù)線程隨著JVM一同結(jié)束工作。
User和Daemon兩者幾乎沒(méi)有區(qū)別,唯一的不同之處就在于虛擬機(jī)的離開(kāi):如果 User Thread已經(jīng)全部退出運(yùn)行了,只剩下Daemon Thread存在了,虛擬機(jī)也就退出了。
因?yàn)闆](méi)有了被守護(hù)者,Daemon也就沒(méi)有工作可做了,也就沒(méi)有繼續(xù)運(yùn)行程序的必要了。
任何線程都可以設(shè)置為守護(hù)線程和用戶線程,通過(guò)方法Thread.setDaemon(bool on);true則把該線程設(shè)置為守護(hù)線程,反之則為用戶線程。Thread.setDaemon()必須在Thread.start()之前調(diào)用,否則運(yùn)行時(shí)會(huì)拋出異常。
守護(hù)線程相當(dāng)于后臺(tái)管理者 比如 : 進(jìn)行內(nèi)存回收,垃圾清理等工作
1、新建狀態(tài)(New):新創(chuàng)建了一個(gè)線程對(duì)象。
2、就緒狀態(tài)(Runnable):線程對(duì)象創(chuàng)建后,其他線程調(diào)用了該對(duì)象的start()方法。該狀態(tài)的線程位于可運(yùn)行線程池中,變得可運(yùn)行,等待獲取CPU的使用權(quán)。
3、運(yùn)行狀態(tài)(Running):就緒狀態(tài)的線程獲取了CPU,執(zhí)行程序代碼。
4、阻塞狀態(tài)(Blocked):阻塞狀態(tài)是線程因?yàn)槟撤N原因放棄CPU使用權(quán),暫時(shí)停止運(yùn)行。直到線程進(jìn)入就緒狀態(tài),才有機(jī)會(huì)轉(zhuǎn)到運(yùn)行狀態(tài)。阻塞的情況分三種: (一)、等待阻塞:運(yùn)行的線程執(zhí)行wait()方法,JVM會(huì)把該線程放入等待池中。(wait會(huì)釋放持有的鎖) (二)、同步阻塞:運(yùn)行的線程在獲取對(duì)象的同步鎖時(shí),若該同步鎖被別的線程占用,則JVM會(huì)把該線程放入鎖池中。 (三)、其他阻塞:運(yùn)行的線程執(zhí)行sleep()或join()方法,或者發(fā)出了I/O請(qǐng)求時(shí),JVM會(huì)把該線程置為阻塞狀態(tài)。當(dāng)sleep()狀態(tài)超時(shí)、join()等待線程終止或者超時(shí)、或者I/O處理完畢時(shí),線程重新轉(zhuǎn)入就緒狀態(tài)。(注意,sleep是不會(huì)釋放持有的鎖)
5、死亡狀態(tài)(Dead):線程執(zhí)行完了或者因異常退出了run()方法,該線程結(jié)束生命周期。
Java提供的終止方法只有一個(gè)stop,但是不建議使用此方法,因?yàn)樗幸韵氯齻€(gè)問(wèn)題:
stop方法是過(guò)時(shí)的 從Java編碼規(guī)則來(lái)說(shuō),已經(jīng)過(guò)時(shí)的方式不建議采用.
stop方法會(huì)導(dǎo)致代碼邏輯不完整 stop方法是一種”惡意”的中斷,一旦執(zhí)行stop方法,即終止當(dāng)前正在運(yùn)行的線程,不管線程邏輯是否完整,這是非常危險(xiǎn)的.
?
網(wǎng)站標(biāo)題:25道多線程面試題(一)
鏈接地址:http://www.rwnh.cn/article26/jdigcg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站維護(hù)、面包屑導(dǎo)航、標(biāo)簽優(yōu)化、做網(wǎng)站、靜態(tài)網(wǎng)站、網(wǎng)站制作
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)