多線程的基本概念?? 程序? 進(jìn)程? 線程
多線程是Java語言的重要特性,大量應(yīng)用于網(wǎng)絡(luò)編程、服務(wù)器端程序的開發(fā)镐侯,最常見的UI界面底層原理、操作系統(tǒng)底層原理都大量使用了多線程驶冒。
程序
“程序(Program)”是一個靜態(tài)的概念苟翻,一般對應(yīng)于操作系統(tǒng)中的一個可執(zhí)行文件,比如:我們要啟動酷狗聽音樂只怎,則對應(yīng)酷狗的可執(zhí)行程序袜瞬。當(dāng)我們雙擊酷狗,則加載程序到內(nèi)存中身堡,開始執(zhí)行該程序邓尤,于是產(chǎn)生了“進(jìn)程”。
進(jìn)程?
執(zhí)行中的程序叫做進(jìn)程(Process)贴谎,是一個動態(tài)的概念」現(xiàn)代的操作系統(tǒng)都可以同時啟動多個進(jìn)程。比如:我們在用酷狗聽音樂擅这,也可以使用eclipse寫代碼澈魄,也可以同時用瀏覽器查看網(wǎng)頁。進(jìn)程具有如下特點:
? ? ??1. 進(jìn)程是程序的一次動態(tài)執(zhí)行過程仲翎, 占用特定的地址空間痹扇。
? ? ??2. 每個進(jìn)程由3部分組成:cpu、data、code。每個進(jìn)程都是獨立的牍颈,保有自己的cpu時間肆氓,代碼和數(shù)據(jù)秽晚,即便用同一份程序產(chǎn)生好幾個進(jìn)程,它們之間還是擁有自己的這3樣?xùn)|西,這樣的缺點是:浪費內(nèi)存演侯,cpu的負(fù)擔(dān)較重炕吸。
? ? ??3. 多任務(wù)(Multitasking)操作系統(tǒng)將CPU時間動態(tài)地劃分給每個進(jìn)程伐憾,操作系統(tǒng)同時執(zhí)行多個進(jìn)程,每個進(jìn)程獨立運行赫模。以進(jìn)程的觀點來看树肃,它會以為自己獨占CPU的使用權(quán)。
線程
?一個進(jìn)程可以產(chǎn)生多個線程瀑罗。同多個進(jìn)程可以共享操作系統(tǒng)的某些資源一樣扫外,同一進(jìn)程的多個線程也可以共享此進(jìn)程的某些資源(比如:代碼、數(shù)據(jù))廓脆,所以線程又被稱為輕量級進(jìn)程(lightweight process)。
? ? ??1. 一個進(jìn)程內(nèi)部的一個執(zhí)行單元磁玉,它是程序中的一個單一的順序控制流程停忿。
? ? ??2. 一個進(jìn)程可擁有多個并行的(concurrent)線程。
? ? ??3. 一個進(jìn)程中的多個線程共享相同的內(nèi)存單元/內(nèi)存地址空間蚊伞,可以訪問相同的變量和對象席赂,而且它們從同一堆中分配對象并進(jìn)行通信、數(shù)據(jù)交換和同步操作时迫。
? ? ??4. 由于線程間的通信是在同一地址空間上進(jìn)行的颅停,所以不需要額外的通信機(jī)制,這就使得通信更簡便而且信息傳遞的速度也更快掠拳。
? ? ??5. 線程的啟動癞揉、中斷、消亡溺欧,消耗的資源非常少喊熟。
通過繼承Thread類實現(xiàn)多線程
繼承Thread類實現(xiàn)多線程的步驟:
? ? ??1. 在Java中負(fù)責(zé)實現(xiàn)線程功能的類是java.lang.Thread 類。
? ? ??2. 可以通過創(chuàng)建 Thread的實例來創(chuàng)建新的線程姐刁。
? ? ??3. 每個線程都是通過某個特定的Thread對象所對應(yīng)的方法run( )來完成其操作的芥牌,方法run( )稱為線程體。
? ? ??4. 通過調(diào)用Thread類的start()方法來啟動一個線程聂使。
課堂代碼:
通過Runnable接口實現(xiàn)多線程
在開發(fā)中壁拉,我們應(yīng)用更多的是通過Runnable接口實現(xiàn)多線程。這種方式克服了11.2.1節(jié)中實現(xiàn)線程類的缺點柏靶,即在實現(xiàn)Runnable接口的同時還可以繼承某個類弃理。所以實現(xiàn)Runnable接口的方式要通用一些。
靜態(tài)代理模式:
課堂代碼:
運行結(jié)果:
線程狀態(tài)
?一個線程對象在它的生命周期內(nèi)宿礁,需要經(jīng)歷5個狀態(tài)案铺。
新生狀態(tài)(New)
? ? ??用new關(guān)鍵字建立一個線程對象后,該線程對象就處于新生狀態(tài)。處于新生狀態(tài)的線程有自己的內(nèi)存空間控汉,通過調(diào)用start方法進(jìn)入就緒狀態(tài)笔诵。
??就緒狀態(tài)(Runnable)
? ? ??處于就緒狀態(tài)的線程已經(jīng)具備了運行條件,但是還沒有被分配到CPU姑子,處于“線程就緒隊列”乎婿,等待系統(tǒng)為其分配CPU。就緒狀態(tài)并不是執(zhí)行狀態(tài)街佑,當(dāng)系統(tǒng)選定一個等待執(zhí)行的Thread對象后谢翎,它就會進(jìn)入執(zhí)行狀態(tài)。一旦獲得CPU沐旨,線程就進(jìn)入運行狀態(tài)并自動調(diào)用自己的run方法森逮。有4中原因會導(dǎo)致線程進(jìn)入就緒狀態(tài):
? ? ??1. 新建線程:調(diào)用start()方法,進(jìn)入就緒狀態(tài);
? ? ??2. 阻塞線程:阻塞解除磁携,進(jìn)入就緒狀態(tài);
? ? ??3. 運行線程:調(diào)用yield()方法褒侧,直接進(jìn)入就緒狀態(tài);
? ? ??4. 運行線程:JVM將CPU資源從本線程切換到其他線程。
??運行狀態(tài)(Running)
? ? ??在運行狀態(tài)的線程執(zhí)行自己run方法中的代碼谊迄,直到調(diào)用其他方法而終止或等待某資源而阻塞或完成任務(wù)而死亡闷供。如果在給定的時間片內(nèi)沒有執(zhí)行結(jié)束,就會被系統(tǒng)給換下來回到就緒狀態(tài)统诺。也可能由于某些“導(dǎo)致阻塞的事件”而進(jìn)入阻塞狀態(tài)歪脏。
??阻塞狀態(tài)(Blocked)
? ? ??阻塞指的是暫停一個線程的執(zhí)行以等待某個條件發(fā)生(如某資源就緒)。有4種原因會導(dǎo)致阻塞:
? ? ??1. 執(zhí)行sleep(int millsecond)方法粮呢,使當(dāng)前線程休眠婿失,進(jìn)入阻塞狀態(tài)。當(dāng)指定的時間到了后啄寡,線程進(jìn)入就緒狀態(tài)移怯。
? ? ??2. 執(zhí)行wait()方法,使當(dāng)前線程進(jìn)入阻塞狀態(tài)这难。當(dāng)使用nofity()方法喚醒這個線程后舟误,它進(jìn)入就緒狀態(tài)。
? ? ??3. 線程運行時姻乓,某個操作進(jìn)入阻塞狀態(tài)嵌溢,比如執(zhí)行IO流操作(read()/write()方法本身就是阻塞的方法)。只有當(dāng)引起該操作阻塞的原因消失后蹋岩,線程進(jìn)入就緒狀態(tài)赖草。
? ? ??4. join()線程聯(lián)合: 當(dāng)某個線程等待另一個線程執(zhí)行結(jié)束后,才能繼續(xù)執(zhí)行時剪个,使用join()方法秧骑。
??死亡狀態(tài)(Terminated)
? ? ??死亡狀態(tài)是線程生命周期中的最后一個階段。線程死亡的原因有兩個。一個是正常運行的線程完成了它run()方法內(nèi)的全部工作; 另一個是線程被強制終止乎折,如通過執(zhí)行stop()或destroy()方法來終止一個線程(注:stop()/destroy()方法已經(jīng)被JDK廢棄绒疗,不推薦使用)。
? ? ??當(dāng)一個線程進(jìn)入死亡狀態(tài)以后骂澄,就不能再回到其它狀態(tài)了吓蘑。
暫停線程執(zhí)行
?暫停線程執(zhí)行常用的方法有sleep()和yield()方法,這兩個方法的區(qū)別是:
? ? ??1. sleep()方法:可以讓正在運行的線程進(jìn)入阻塞狀態(tài)坟冲,直到休眠時間滿了磨镶,進(jìn)入就緒狀態(tài)。
? ? ??2. yield()方法:可以讓正在運行的線程直接進(jìn)入就緒狀態(tài)健提,讓出CPU的使用權(quán)琳猫。
課堂代碼:
獲取線程基本信息的方法
課堂代碼:
測試isAlive();
測試getName()
線程同步
處理多線程問題時私痹,多個線程訪問同一個對象沸移,并且某些線程還想修改這個對象。 這時候侄榴,我們就需要用到“線程同步”。 線程同步其實就是一種等待機(jī)制网沾,多個需要同時訪問此對象的線程進(jìn)入這個對象的等待池形成隊列癞蚕,等待前面的線程使用完畢后,下一個線程再使用
實現(xiàn)線程同步:
由于同一進(jìn)程的多個線程共享同一塊存儲空間辉哥,在帶來方便的同時桦山,也帶來了訪問沖突的問題。Java語言提供了專門機(jī)制以解決這種沖突醋旦,有效避免了同一個數(shù)據(jù)對象被多個線程同時訪問造成的這種問題恒水。
包括兩種用法:synchronized 方法和 synchronized 塊。
課堂代碼:
死鎖及解決方案
死鎖”指的是:
? ? ??多個線程各自占有一些共享資源饲齐,并且互相等待其他線程占有的資源才能進(jìn)行钉凌,而導(dǎo)致兩個或者多個線程都在等待對方釋放資源,都停止執(zhí)行的情形捂人。
死鎖的解決方法
? ? ? 死鎖是由于“同步塊需要同時持有多個對象鎖造成”的御雕,要解決這個問題,思路很簡單滥搭,就是:同一個代碼塊酸纲,不要同時持有兩個對象鎖。