1顺呕、概念
基本概念
進程:就是電腦中一個一個的正在執(zhí)行的應(yīng)用程序枫攀;
線程:負責(zé)執(zhí)行這個程序的執(zhí)行單元;
單線程:效率低株茶,但是安全来涨;
多線程:效率高,但是數(shù)據(jù)不安全启盛;
進程和線程的理解:
操作系統(tǒng)可以同時執(zhí)行多個任務(wù)蹦掐,每個任務(wù)就是進程;進程可以同時執(zhí)行多個任務(wù)僵闯,每個任務(wù)就是線程卧抗。(通常一個任務(wù)就是一個程序,每個運行中的程序就是一個進程鳖粟。一個程序運行時社裆,內(nèi)部可能包含了多個順序執(zhí)行流,每個順序執(zhí)行流就是一個線程)
多線程的優(yōu)點:
1.進程之間不能共享內(nèi)存牺弹,但是線程之間共享內(nèi)存非常容易。
2.系統(tǒng)創(chuàng)建進程時需要為該進程重新分配系統(tǒng)資源时呀,但創(chuàng)建線程代價小得多张漂,因此使用多線程來實現(xiàn)多任務(wù)并發(fā)比多進程的效率高。
3.Java語言內(nèi)置了多線程功能支持谨娜,而不是單純地作為底層操作系統(tǒng)的調(diào)度方式航攒,簡化了Java的多線程編程。
2趴梢、多線程實現(xiàn)方式
方式一:
1漠畜、自定義一個繼承Thread類币他,重寫run()方法;
2憔狞、創(chuàng)建Thread子類對象蝴悉,調(diào)用start()方法,開啟線程瘾敢;
使用繼承Thread類的方法創(chuàng)建線程類時拍冠,多個線程之間無法共享線程類的成員變量(子類定義的成員變量)。
方式二:推薦使用
1簇抵、自定義一個類庆杜,實現(xiàn)Runnable接口,重寫run()方法碟摆;
2晃财、創(chuàng)建Thread對象,創(chuàng)建該類對象典蜕, 通過Thread類構(gòu)造方法断盛,把該類對象傳進去;
3嘉裤、調(diào)用Thread類的start()方法開啟線程郑临;
實現(xiàn)Runnable接口的方式,多個線程可以共享同一個線程類的成員變量屑宠。
方式三:使用Callable和Future創(chuàng)建線程
創(chuàng)建線程的三種方式對比(實現(xiàn)接口和繼承Thread類):
實現(xiàn)Runnable或Callable接口創(chuàng)建多線程
優(yōu)點:
1.線程類只是實現(xiàn)了接口厢洞,還可以繼承其他的類;
2.多個線程可以共享同一個target對象典奉,非常適合多個線程來處理同一份資源的情況躺翻,從而可以將CPU、代碼和數(shù)據(jù)分開卫玖,形成清晰地模型公你,較好地體現(xiàn)了面向?qū)ο蟮乃枷耄?br>
缺點:
1.編程稍微復(fù)雜,如果需要訪問當前線程假瞬,則必須使Thread.currentThread()方法陕靠;
繼承Thread類創(chuàng)建多線程:
優(yōu)點:編寫簡單,如果需要訪問當前線程脱茉,直接 使用this可以獲得當前線程剪芥;
缺點:不能再繼承其他父類;
3琴许、線程的生命周期
新建:使用new關(guān)鍵字創(chuàng)建一個線程税肪;
此時,僅僅Java虛擬機為其分配內(nèi)存,并初始化其成員變量的值益兄。
就緒:調(diào)用start()方法后锻梳,線程處于就緒狀態(tài),等待獲取CPU的使用權(quán)净捅。
此時疑枯,具備了執(zhí)行條件,不具備執(zhí)行權(quán)利灸叼。
運行:就緒狀態(tài)的線程得到CPU的使用權(quán)后神汹,進入運行狀態(tài)。
此時古今,具備了執(zhí)行條件屁魏,具備了執(zhí)行權(quán)利。
等待:運行狀態(tài)下的線程捉腥,調(diào)用thread類中的wait()方法氓拼,線程進入等待狀態(tài)。
此時抵碟,必須調(diào)用thread類中的notify()方法才能被喚醒桃漾,喚醒后處于就緒狀態(tài)。
休眠:運行狀態(tài)下的線程拟逮,調(diào)用thread類中的sleep()方法撬统,則會進入休眠狀態(tài)。休眠時間結(jié)束后敦迄,進入就緒狀態(tài)恋追;
阻塞:運行狀態(tài)下的線程,發(fā)出輸入/輸出請求時罚屋,線程進入阻塞狀態(tài)苦囱,等待輸入/輸出結(jié)束時線程進入就緒狀態(tài)。對于阻塞的線程脾猛,即使系統(tǒng)資源空閑撕彤,線程依然不能回到運行狀態(tài)。
死亡:三種情況:
1.當線程的run()方法或call()方法執(zhí)行完畢后猛拴,線程進入死亡狀態(tài)羹铅。
2.線程拋出一個未捕獲的Exception或Error
3.直接調(diào)用該線程的stop()方法來結(jié)束該線程。(該方法容易導(dǎo)致死鎖愉昆,不推薦使用)
Note:不能對一個已經(jīng)死亡的線程調(diào)用start()方法使他重新啟動职员,死亡就是死亡,該線程將不可能再次作為線程執(zhí)行撼唾。對死亡的線程調(diào)用start()方法或?qū)π聞?chuàng)建的線程兩次調(diào)用start()方法廉邑,會引發(fā)IllegalThreadStateException異常;
//當線程在同步代碼塊中倒谷,sleep()和wait()的區(qū)別就很明顯蛛蒙。
4、同步方法和同步代碼塊
同步方法:(使用同步方法可以非常方便地實現(xiàn)線程安全的類)
用synchronized關(guān)鍵字修飾的方法渤愁,作用是每次只允許一條線程進入方法執(zhí)行代碼牵祟;
靜態(tài)同步方法:本類的字節(jié)碼對象;
非靜態(tài)同步方法:無須顯示指定同步監(jiān)視器抖格,同步方法的監(jiān)視器是this诺苹,也就是調(diào)用該方法的對象。
同步代碼塊:
一個用synchronized關(guān)鍵字修飾的代碼塊雹拄,這個代碼塊中的代碼是被鎖住的代碼收奔,每次只允許一條線程來執(zhí)行;
必須確保同步代碼塊的鎖對象唯一滓玖;//所對象為被訪問的共享資源作為同步監(jiān)視器坪哄。
synchronized(obj){
//此處的代碼就是同步代碼塊
}
其中,obj是同步監(jiān)視器,代碼的含義是:線程開始執(zhí)行同步代碼塊之前势篡,必須先獲得對同步監(jiān)視器的鎖定翩肌。任何時刻只能有一個線程可以獲得對同步監(jiān)視器的鎖定,當同步代碼塊執(zhí)行完成后禁悠,該線程會釋放對該同步監(jiān)視器的鎖定念祭。
同步監(jiān)視器的目的:阻止兩個線程對同一個共享資源進行并發(fā)訪問。因此通常使用可能被并發(fā)訪問的共享資源充當同步監(jiān)視器碍侦。
線程安全的類具有如下特征:
該類的對象可以被多個線程安全地訪問粱坤。
每個線程調(diào)用該對象的任意方法之后都可以得到正確結(jié)果;
可變類和不可變類:
不可變類總是線程安全的祝钢,因為它的對象狀態(tài)不可改變比规,但可變對象需要額外的方法來保證其線程安全。