1.Object類是所有類的父類(Object提供了11 個(gè)方法)
1. clone()
保護(hù)方法,實(shí)現(xiàn)對(duì)象的淺復(fù)制定罢,只有實(shí)現(xiàn)了Cloneable接口才可以調(diào)用該方法,否則拋出CloneNotSupportedException異常旁瘫。
2. getClass()
final方法祖凫,返回Class類型的對(duì)象,反射來獲取對(duì)象境蜕。
3. toString()
該方法用得比較多蝙场,一般子類都有覆蓋,來獲取對(duì)象的信息粱年。
4. finalize()
該方法用于釋放資源售滤。因?yàn)闊o法確定該方法什么時(shí)候被調(diào)用,很少使用台诗。
5. equals()
比較對(duì)象的內(nèi)容是否相等
6. hashCode()
該方法用于哈希查找完箩,重寫了equals方法一般都要重寫hashCode方法。這個(gè)方法在一些具有哈希功能的Collection中用到拉队。
7. wait()
wait方法就是使當(dāng)前線程等待該對(duì)象的鎖弊知,當(dāng)前線程必須是該對(duì)象的擁有者,也就是具有該對(duì)象的鎖粱快。wait()方法一直等待秩彤,直到獲得鎖或者被中斷叔扼。wait(long timeout)設(shè)定一個(gè)超時(shí)間隔,如果在規(guī)定時(shí)間內(nèi)沒有獲得鎖就返回漫雷。
調(diào)用該方法后當(dāng)前線程進(jìn)入睡眠狀態(tài)瓜富,直到以下事件發(fā)生。
其他線程調(diào)用了該對(duì)象的notify方法降盹。
其他線程調(diào)用了該對(duì)象的notifyAll方法与柑。
其他線程調(diào)用了interrupt中斷該線程。
時(shí)間間隔到了蓄坏。
此時(shí)該線程就可以被調(diào)度了价捧,如果是被中斷的話就拋出一個(gè)InterruptedException異常。
8. notify()
該方法喚醒在該對(duì)象上等待的某個(gè)線程涡戳。
9. notifyAll()
該方法喚醒在該對(duì)象上等待的所有線程结蟋。
2.JVM的構(gòu)成
1. 類加載子系統(tǒng)(Class Loader)
功能:負(fù)責(zé)從文件系統(tǒng)或網(wǎng)絡(luò)中加載Class信息。加載的類信息被存放在方法區(qū)渔彰。
特點(diǎn):類加載器只管加載椎眯,只要符合文件結(jié)構(gòu)就加載,至于能否運(yùn)行胳岂,則由執(zhí)行引擎負(fù)責(zé)。
啟動(dòng)類加載器(Bootstrap ClassLoader):用于加載Java核心類庫(kù)舔稀。
擴(kuò)展類加載器(Extension ClassLoader):用于加載額外的類庫(kù)乳丰。
應(yīng)用程序類加載器(Application ClassLoader):用于加載應(yīng)用程序的類。
2. 運(yùn)行時(shí)數(shù)據(jù)區(qū)(Runtime Data Areas)
運(yùn)行時(shí)數(shù)據(jù)區(qū)是JVM的核心內(nèi)存空間結(jié)構(gòu)模型内贮,包含以下幾個(gè)部分:
程序計(jì)數(shù)器(Program Counter Register)
功能:指示Java虛擬機(jī)下一條需要執(zhí)行的字節(jié)碼指令产园。
特點(diǎn):占用內(nèi)存空間較小,是線程私有的夜郁。
Java虛擬機(jī)棧(VM Stack)
功能:每個(gè)虛擬機(jī)線程都有一個(gè)私有的棧什燕,用來保存局部變量、方法參數(shù)以及方法的調(diào)用和返回值等信息竞端。
特點(diǎn):線程私有屎即,隨線程的創(chuàng)建而創(chuàng)建,隨線程的結(jié)束而銷毀事富。
本地方法棧(Native Method Stack)
功能:與Java虛擬機(jī)棧類似技俐,但主要用于執(zhí)行本地方法(如C語(yǔ)言編寫的方法)。
特點(diǎn):線程私有统台。
Java堆(Heap)
功能:是Java程序最主要的內(nèi)存工作區(qū)域雕擂,用于存放對(duì)象實(shí)例和數(shù)組。
特點(diǎn):線程共享贱勃,在JVM啟動(dòng)時(shí)創(chuàng)建井赌。堆被劃分為年輕代谤逼、老年代和永久代(在JDK8中取消了永久代,引入了元空間Meta Space)仇穗。
方法區(qū)(Method Area)
功能:用于存儲(chǔ)已被虛擬機(jī)加載的類信息流部、常量、靜態(tài)變量仪缸、即時(shí)編譯器編譯后的代碼等數(shù)據(jù)贵涵。
特點(diǎn):線程共享。在JDK8之前恰画,方法區(qū)屬于永久代宾茂;在JDK8及之后,永久代被移除拴还,方法區(qū)被移到了本地內(nèi)存中跨晴,即元空間。
3. 執(zhí)行引擎(Execution Engine)
功能:執(zhí)行虛擬機(jī)的字節(jié)碼片林,將其轉(zhuǎn)換成機(jī)器碼后執(zhí)行端盆。
特點(diǎn):JVM的核心組件,負(fù)責(zé)解釋和執(zhí)行Java字節(jié)碼费封。
4. 本地庫(kù)接口(Native Interface)
功能:作為JVM與操作系統(tǒng)之間的橋梁焕妙,融合不同的開發(fā)語(yǔ)言為Java所用。
特點(diǎn):允許Java調(diào)用其他語(yǔ)言(如C語(yǔ)言)編寫的代碼和庫(kù)弓摘。
5. 垃圾收集系統(tǒng)(Garbage Collection System)
功能:自動(dòng)管理內(nèi)存焚鹊,回收不再被使用的對(duì)象所占用的內(nèi)存空間。
特點(diǎn):Java的核心機(jī)制之一韧献,減輕了開發(fā)人員的內(nèi)存管理負(fù)擔(dān)末患。
2.1
類加載系統(tǒng)的運(yùn)行流程
1.加載(Loading)
功能:通過一個(gè)類的全限定名獲取定義此類的二進(jìn)制字節(jié)流,將這個(gè)字節(jié)流所代表的靜態(tài)存儲(chǔ)結(jié)構(gòu)轉(zhuǎn)化為方法區(qū)的運(yùn)行時(shí)數(shù)據(jù)結(jié)構(gòu)锤窑,在內(nèi)存中生成一個(gè)代表這個(gè)類的java.lang.Class對(duì)象璧针,作為方法區(qū)這個(gè)類的各種數(shù)據(jù)的訪問入口。
方式:加載.class文件的方式多樣渊啰,可以從本地系統(tǒng)中直接加載探橱、從網(wǎng)絡(luò)獲取、從zip壓縮文件中讀人涑(如jar走搁、war包)、運(yùn)行時(shí)計(jì)算生成(如動(dòng)態(tài)代理技術(shù))迈窟、由其他文件生成(如JSP)等私植。
2.連接(Linking)
驗(yàn)證(Verification):確保加載的類信息符合JVM規(guī)范,沒有安全方面的問題车酣。主要包括文件格式驗(yàn)證曲稼、元數(shù)據(jù)驗(yàn)證索绪、字節(jié)碼驗(yàn)證和符號(hào)引用驗(yàn)證。
準(zhǔn)備(Preparation):為類的靜態(tài)變量分配內(nèi)存贫悄,并設(shè)置這些變量的默認(rèn)初始值(通常是零值瑞驱,但final修飾的static變量在編譯時(shí)就已經(jīng)賦值)。
解析(Resolution):將常量池中的符號(hào)引用替換為直接引用的過程窄坦。這通常發(fā)生在初始化階段之前唤反,但也可能在某些情況下在初始化階段之后進(jìn)行,以支持Java語(yǔ)言的運(yùn)行時(shí)綁定鸭津。
3.初始化(Initialization)
功能:執(zhí)行類構(gòu)造器<clinit>()方法的過程彤侍。這個(gè)方法由編譯器自動(dòng)收集類中的所有類變量的賦值動(dòng)作和靜態(tài)語(yǔ)句塊(static塊)中的語(yǔ)句合并產(chǎn)生。
特點(diǎn):<clinit>()方法不需要定義逆趋,且在多線程環(huán)境下被正確加鎖和同步盏阶,以確保一個(gè)類的<clinit>()方法在多線程環(huán)境中只被執(zhí)行一次。
4.使用(Using)
功能:類被初始化后闻书,其方法就可以被JVM調(diào)用名斟,類的實(shí)例也可以被創(chuàng)建和使用。
5.卸載(Unloading)
功能:當(dāng)類不再被需要時(shí)(如程序執(zhí)行完畢或類加載器被回收)魄眉,JVM會(huì)卸載這個(gè)類砰盐,釋放其占用的資源。
1.雙親委派模型(Parent Delegation Model)
功能:這是一種類加載器的層次結(jié)構(gòu)模型坑律,要求除了頂層的啟動(dòng)類加載器外楞卡,其余的類加載器都應(yīng)當(dāng)有自己的父類加載器。當(dāng)一個(gè)類加載器需要加載某個(gè)類時(shí)脾歇,它會(huì)先委托給父類加載器去加載,只有當(dāng)父類加載器無法加載時(shí)淘捡,才由自己去加載藕各。
目的:這種模型的主要目的是確保Java核心庫(kù)的類型安全,防止用戶自定義的類覆蓋Java的核心類焦除。
2.緩存機(jī)制
功能:類加載器在加載類時(shí)會(huì)緩存已加載的類信息激况,以避免重復(fù)加載。這通常是通過在內(nèi)存中維護(hù)一個(gè)已加載類的映射表來實(shí)現(xiàn)的膘魄。
目的:提高類加載的效率乌逐,減少內(nèi)存消耗。
3.動(dòng)態(tài)代理技術(shù)
功能:動(dòng)態(tài)代理是一種在運(yùn)行時(shí)動(dòng)態(tài)創(chuàng)建接口實(shí)現(xiàn)類的技術(shù)创葡。通過動(dòng)態(tài)代理浙踢,可以在不修改原有類代碼的情況下,為類添加新的行為灿渴。
實(shí)現(xiàn)方式:在類加載過程中洛波,動(dòng)態(tài)代理技術(shù)可以通過加載時(shí)計(jì)算生成代理類的字節(jié)碼胰舆,并將其加載到JVM中,從而實(shí)現(xiàn)對(duì)原有類的增強(qiáng)蹬挤。
舉例說明
假設(shè)我們有一個(gè)自定義的類com.example.MyClass缚窿,位于項(xiàng)目的classpath目錄下,現(xiàn)在需要加載這個(gè)類焰扳。
應(yīng)用程序類加載器(Application ClassLoader)接收任務(wù):
當(dāng)Java虛擬機(jī)需要加載com.example.MyClass類時(shí)倦零,首先會(huì)由系統(tǒng)類加載器(即應(yīng)用程序類加載器)接收這個(gè)任務(wù)。
向上委托:
應(yīng)用程序類加載器會(huì)先檢查自己是否已經(jīng)加載過這個(gè)類(即檢查方法區(qū)中是否已經(jīng)存在該類的Class對(duì)象)吨悍。如果沒有扫茅,它會(huì)將這個(gè)加載請(qǐng)求委托給它的父類加載器——擴(kuò)展類加載器。
擴(kuò)展類加載器同樣會(huì)先檢查自己是否已經(jīng)加載過這個(gè)類畜份,如果沒有诞帐,它會(huì)繼續(xù)將這個(gè)任務(wù)委托給它的父類加載器——引導(dǎo)類加載器。
引導(dǎo)類加載器嘗試加載:
引導(dǎo)類加載器會(huì)檢查自己負(fù)責(zé)的區(qū)域(主要是Java的核心庫(kù))中是否存在這個(gè)類爆雹。由于com.example.MyClass顯然不是Java的核心類停蕉,因此引導(dǎo)類加載器無法加載這個(gè)類。
向下查找加載:
既然父類加載器無法加載這個(gè)類钙态,任務(wù)就會(huì)回傳給子類加載器慧起。首先,擴(kuò)展類加載器會(huì)在它負(fù)責(zé)的區(qū)域(JRE_HOME/lib/ext目錄)中查找這個(gè)類册倒,但同樣找不到蚓挤。
最后,任務(wù)回傳給應(yīng)用程序類加載器驻子,它會(huì)在用戶類路徑(classpath)下查找這個(gè)類灿意,并成功找到com.example.MyClass的.class文件,然后加載這個(gè)類到JVM中崇呵。
2.1?垃圾回收的運(yùn)行流程
1. 判定垃圾對(duì)象
JVM通過一定的算法來判斷哪些對(duì)象是“垃圾”缤剧,即不再被使用的對(duì)象。常用的判定算法有兩種:
引用計(jì)數(shù)法(Reference Counting):為每個(gè)對(duì)象維護(hù)一個(gè)引用計(jì)數(shù)器域慷,每當(dāng)有一個(gè)地方引用它時(shí)荒辕,計(jì)數(shù)器就加1;當(dāng)引用失效時(shí)犹褒,計(jì)數(shù)器就減1抵窒。任何時(shí)刻計(jì)數(shù)器為0的對(duì)象就是不可達(dá)對(duì)象,即垃圾對(duì)象叠骑。但這種方法存在循環(huán)引用的問題李皇,因此JVM實(shí)際使用中并未采用。
可達(dá)性分析算法(Reachability Analysis):通過一系列稱為“GC Roots”的根對(duì)象作為起始點(diǎn)宙枷,從這些根對(duì)象開始向下搜索疙赠,所走過的路徑稱為引用鏈(Reference Chain)付材。如果一個(gè)對(duì)象到GC Roots沒有任何引用鏈相連,即該對(duì)象是不可達(dá)的圃阳,則證明此對(duì)象是不可用的厌衔,可以判定為垃圾對(duì)象。
2.垃圾回收的執(zhí)行階段
選擇垃圾回收算法:
標(biāo)記-清除算法(Mark-Sweep):首先標(biāo)記出所有需要回收的對(duì)象捍岳,然后統(tǒng)一回收這些對(duì)象所占用的內(nèi)存空間富寿。這種方法簡(jiǎn)單但容易產(chǎn)生內(nèi)存碎片。
復(fù)制算法(Copying):將內(nèi)存分為大小相同的兩塊锣夹,每次只使用其中一塊页徐。當(dāng)這塊內(nèi)存快滿時(shí),就將還存活的對(duì)象復(fù)制到另一塊內(nèi)存上银萍,然后清理掉正在使用的內(nèi)存塊中的所有對(duì)象变勇。這種方法效率高,但內(nèi)存利用率低贴唇。
標(biāo)記-整理算法(Mark-Compact):結(jié)合了標(biāo)記-清除算法和復(fù)制算法的特點(diǎn)搀绣,首先標(biāo)記出所有需要回收的對(duì)象,然后將所有存活的對(duì)象壓縮到內(nèi)存的一端戳气,最后清理掉邊界以外的內(nèi)存链患。這種方法避免了內(nèi)存碎片的產(chǎn)生,同時(shí)提高了內(nèi)存利用率瓶您。
執(zhí)行垃圾回收:
根據(jù)選擇的垃圾回收算法麻捻,JVM會(huì)執(zhí)行相應(yīng)的垃圾回收操作。以復(fù)制算法為例呀袱,當(dāng)新生代中的Eden區(qū)(伊甸區(qū))快滿時(shí)贸毕,JVM會(huì)觸發(fā)一次Minor GC(年輕代垃圾回收):
將Eden區(qū)中還存活的對(duì)象復(fù)制到一個(gè)Survivor區(qū)(幸存區(qū))中;
如果Survivor區(qū)也滿了夜赵,就將該Survivor區(qū)中還存活的對(duì)象復(fù)制到另一個(gè)Survivor區(qū)中崖咨,并清空原Survivor區(qū)的所有對(duì)象;
經(jīng)過多次GC后油吭,如果對(duì)象仍然存活,則將其晉升到老年代中署拟。
現(xiàn)在使用可達(dá)性分析算法而不是引用計(jì)數(shù)法作為JVM(Java虛擬機(jī))中的主流垃圾回收算法婉宰,主要基于以下幾個(gè)原因:
一、引用計(jì)數(shù)法的缺陷
無法解決循環(huán)引用問題:
引用計(jì)數(shù)法通過為每個(gè)對(duì)象維護(hù)一個(gè)引用計(jì)數(shù)器來記錄其被引用的次數(shù)推穷。然而心包,當(dāng)兩個(gè)或多個(gè)對(duì)象相互引用形成循環(huán)時(shí),即使這些對(duì)象已經(jīng)不再被程序中的其他部分所使用馒铃,它們的引用計(jì)數(shù)器也不會(huì)變?yōu)榱阈诽冢虼藷o法被垃圾回收器回收痕惋。這種情況下,會(huì)導(dǎo)致內(nèi)存泄漏娃殖。
增加內(nèi)存開銷:
引用計(jì)數(shù)法需要為每個(gè)對(duì)象額外存儲(chǔ)一個(gè)引用計(jì)數(shù)器值戳,這增加了內(nèi)存的占用。在對(duì)象數(shù)量龐大的情況下炉爆,這種額外的內(nèi)存開銷會(huì)變得非常顯著堕虹。
影響性能:
每次對(duì)象的引用發(fā)生變化時(shí)(如賦值、解引用等)芬首,都需要更新相應(yīng)的引用計(jì)數(shù)器赴捞。這個(gè)操作會(huì)增加程序的執(zhí)行時(shí)間,尤其是在多線程環(huán)境下郁稍,為了保證引用計(jì)數(shù)的準(zhǔn)確性赦政,還需要進(jìn)行額外的同步操作,進(jìn)一步降低了性能耀怜。
二恢着、可達(dá)性分析算法的優(yōu)勢(shì)
能夠處理循環(huán)引用:
可達(dá)性分析算法通過一組稱為“GC Roots”的根對(duì)象作為起始點(diǎn),從這些根對(duì)象開始向下搜索封寞,能夠被搜索到的對(duì)象稱為“可達(dá)對(duì)象”然评,而不能被搜索到的對(duì)象則被認(rèn)為是垃圾對(duì)象。這種方法可以有效地解決循環(huán)引用的問題狈究,避免了內(nèi)存泄漏的發(fā)生碗淌。
更高的準(zhǔn)確性:
可達(dá)性分析算法通過對(duì)整個(gè)對(duì)象圖進(jìn)行搜索來確定哪些對(duì)象是可達(dá)的,哪些是不可達(dá)的抖锥。這種方法的準(zhǔn)確性高于引用計(jì)數(shù)法亿眠,因?yàn)樗軌蛱幚砀訌?fù)雜的引用關(guān)系。
更好的內(nèi)存利用率:
在可達(dá)性分析算法中磅废,垃圾回收器會(huì)進(jìn)行兩次標(biāo)記過程來優(yōu)化內(nèi)存布局纳像。第一次標(biāo)記過程將所有可達(dá)對(duì)象標(biāo)記為“存活對(duì)象”,第二次標(biāo)記過程則會(huì)對(duì)存活對(duì)象進(jìn)行再次標(biāo)記拯勉,并重新整理內(nèi)存布局竟趾,消除內(nèi)存碎片。這個(gè)過程可以提高內(nèi)存的利用率和系統(tǒng)的性能宫峦。
適應(yīng)現(xiàn)代JVM的需求:
隨著JVM的發(fā)展岔帽,現(xiàn)代應(yīng)用對(duì)內(nèi)存管理的需求越來越高〉急粒可達(dá)性分析算法作為一種更加成熟和高效的垃圾回收算法犀勒,能夠更好地滿足現(xiàn)代JVM的需求,提供穩(wěn)定可靠的內(nèi)存管理服務(wù)。
綜上所述贾费,由于引用計(jì)數(shù)法存在無法解決循環(huán)引用钦购、增加內(nèi)存開銷和影響性能等缺陷,而可達(dá)性分析算法則具有能夠處理循環(huán)引用褂萧、更高的準(zhǔn)確性和更好的內(nèi)存利用率等優(yōu)勢(shì)押桃,因此現(xiàn)在JVM中普遍采用可達(dá)性分析算法作為主流的垃圾回收算法。
3.java中多線程與線程池
3.1線程的狀態(tài):
1.新建狀態(tài)(New):
新創(chuàng)建了一個(gè)線程對(duì)象箱玷,但還沒有調(diào)用start()方法怨规。此時(shí),線程處于初始化階段锡足,尚未開始執(zhí)行波丰。
2.就緒狀態(tài)(Runnable):
當(dāng)線程對(duì)象創(chuàng)建后,其他線程調(diào)用了該對(duì)象的start()方法舶得,線程進(jìn)入就緒狀態(tài)掰烟。在這個(gè)狀態(tài)下,線程已經(jīng)做好了運(yùn)行的準(zhǔn)備沐批,位于“可運(yùn)行線程池”中纫骑,只等待CPU的分配來執(zhí)行程序代碼。此時(shí)九孩,線程除CPU之外先馆,其他運(yùn)行所需資源都已全部獲得。
3.運(yùn)行狀態(tài)(Running):
當(dāng)就緒狀態(tài)的線程獲取了CPU時(shí)間片后躺彬,線程進(jìn)入運(yùn)行狀態(tài)煤墙,執(zhí)行程序代碼。這是線程執(zhí)行過程中最重要的一個(gè)狀態(tài)宪拥。
4.阻塞狀態(tài)(Blocked):
線程因?yàn)槟撤N原因放棄CPU使用權(quán)仿野,暫時(shí)停止運(yùn)行。阻塞狀態(tài)是線程生命周期中的一種重要狀態(tài)她君,它可以進(jìn)一步細(xì)分為以下幾種情況:
? ??等待阻塞:線程執(zhí)行了wait()方法脚作,會(huì)釋放占用的所有資源,JVM會(huì)把該線程放入“等待池”中缔刹。這個(gè)狀態(tài)不能自動(dòng)喚醒球涛,必須依靠其他線程調(diào)用notify()或notifyAll()方法才能被喚醒。
? ??同步阻塞:線程在獲取對(duì)象的同步鎖時(shí)校镐,如果該同步鎖被其他線程占用亿扁,則JVM會(huì)把該線程放入“鎖池”中等待。
? ??其他阻塞:線程執(zhí)行sleep()或join()方法灭翔,或者發(fā)出了I/O請(qǐng)求時(shí),JVM會(huì)把該線程置為阻塞狀態(tài)。當(dāng)sleep()狀態(tài)超時(shí)肝箱、join()等待線程終止或者超時(shí)哄褒、或者I/O處理完畢時(shí),線程會(huì)重新轉(zhuǎn)入就緒狀態(tài)煌张。
?5.等待狀態(tài)/超時(shí)等待(Waiting/Timed_Waiting):
線程進(jìn)入等待狀態(tài)通常是因?yàn)檎{(diào)用了sleep()或wait()等方法呐赡。與阻塞狀態(tài)類似,但等待狀態(tài)更側(cè)重于線程主動(dòng)放棄CPU使用權(quán)并進(jìn)入等待骏融,而阻塞狀態(tài)可能由外部因素(如I/O請(qǐng)求)導(dǎo)致链嘀。
sleep()是Thread類中的方法,用于讓當(dāng)前線程暫停執(zhí)行一段時(shí)間档玻,但不釋放鎖資源怀泊。wait()是Object類中的方法,用于讓線程放棄當(dāng)前對(duì)象的鎖误趴,并等待其他線程調(diào)用notify()或notifyAll()方法霹琼。
6.終止?fàn)顟B(tài)(Terminated/Dead):
線程執(zhí)行完了或者因異常退出了run()方法,此時(shí)線程結(jié)束生命周期凉当,進(jìn)入終止?fàn)顟B(tài)枣申。一旦線程進(jìn)入終止?fàn)顟B(tài),就不能再被復(fù)生看杭。
3.2線程池的創(chuàng)建方式
1. Executors.newFixedThreadPool(int nThreads)
創(chuàng)建方式:通過Executors工廠類的newFixedThreadPool方法忠藤,可以創(chuàng)建一個(gè)固定大小的線程池。
優(yōu)點(diǎn):
線程池大小固定楼雹,可預(yù)測(cè)性較好模孩,控制線程數(shù)量有助于避免過多的線程競(jìng)爭(zhēng)資源。
線程可以重用烘豹,減少創(chuàng)建和銷毀線程的開銷瓜贾。
缺點(diǎn):
如果任務(wù)過多,超過線程池的大小携悯,那么超出的任務(wù)需要等待線程池中的線程空閑出來才能繼續(xù)執(zhí)行祭芦,可能會(huì)增加任務(wù)的等待時(shí)間。
如果任務(wù)執(zhí)行時(shí)間長(zhǎng)短不一憔鬼,長(zhǎng)時(shí)間執(zhí)行的任務(wù)可能會(huì)導(dǎo)致后續(xù)任務(wù)長(zhǎng)時(shí)間等待龟劲。
2. Executors.newCachedThreadPool()
創(chuàng)建方式:通過Executors工廠類的newCachedThreadPool方法,可以創(chuàng)建一個(gè)可緩存的線程池轴或。
優(yōu)點(diǎn):
線程池的大小不是固定的昌跌,而是根據(jù)需要?jiǎng)討B(tài)調(diào)整的。
如果線程池中的線程空閑超過一定時(shí)間(默認(rèn)為60秒)照雁,則會(huì)被自動(dòng)回收蚕愤。
適用于執(zhí)行大量短期異步任務(wù)的場(chǎng)景,可以提高程序效率。
缺點(diǎn):
可能會(huì)創(chuàng)建大量的線程萍诱,如果任務(wù)執(zhí)行時(shí)間很短悬嗓,且任務(wù)提交頻繁,可能會(huì)導(dǎo)致系統(tǒng)創(chuàng)建大量線程裕坊,增加系統(tǒng)資源消耗包竹。
線程的生命周期較短,頻繁地創(chuàng)建和銷毀線程也會(huì)帶來一定的開銷籍凝。
3. Executors.newSingleThreadExecutor()
創(chuàng)建方式:通過Executors工廠類的newSingleThreadExecutor方法周瞎,可以創(chuàng)建一個(gè)單線程的線程池。
優(yōu)點(diǎn):
線程池中只有一個(gè)線程饵蒂,可以保證任務(wù)按照提交的順序執(zhí)行声诸,避免了并發(fā)執(zhí)行帶來的問題。
適用于需要順序執(zhí)行任務(wù)的場(chǎng)景苹享。
缺點(diǎn):
線程池只有一個(gè)線程双絮,如果任務(wù)執(zhí)行時(shí)間較長(zhǎng),后續(xù)任務(wù)會(huì)長(zhǎng)時(shí)間等待得问。
并發(fā)性能較低囤攀,不適合高并發(fā)的場(chǎng)景。
4. Executors.newScheduledThreadPool(int corePoolSize)
創(chuàng)建方式:通過Executors工廠類的newScheduledThreadPool方法宫纬,可以創(chuàng)建一個(gè)支持定時(shí)及周期性任務(wù)的線程池焚挠。
優(yōu)點(diǎn):
支持定時(shí)任務(wù)和周期性任務(wù)的執(zhí)行。
線程池中的線程可以重用漓骚,減少線程創(chuàng)建和銷毀的開銷蝌衔。
缺點(diǎn):
與固定大小的線程池類似,如果任務(wù)過多蝌蹂,超出的任務(wù)需要等待線程空閑噩斟。
如果任務(wù)執(zhí)行時(shí)間不確定,可能會(huì)影響定時(shí)任務(wù)的準(zhǔn)時(shí)性孤个。
5. ThreadPoolExecutor(直接創(chuàng)建)
創(chuàng)建方式:直接使用ThreadPoolExecutor的構(gòu)造函數(shù)創(chuàng)建線程池剃允,這種方式提供了最全面的配置選項(xiàng)。
優(yōu)點(diǎn):
完全自定義線程池的行為齐鲤,包括核心線程數(shù)斥废、最大線程數(shù)、空閑線程存活時(shí)間给郊、任務(wù)隊(duì)列類型等牡肉。
可以根據(jù)不同的業(yè)務(wù)場(chǎng)景和需求,靈活地配置線程池淆九。
1.corePoolSize(核心線程數(shù)):
定義:線程池中的核心線程數(shù)量统锤,即在沒有任務(wù)需要執(zhí)行時(shí)線程池的基本大小毛俏。這些線程會(huì)一直保持存活,即使它們處于空閑狀態(tài)饲窿。
重要性:決定了線程池能夠處理的最小并發(fā)任務(wù)數(shù)拧抖。
2.maximumPoolSize(最大線程數(shù)):
定義:線程池中允許的最大線程數(shù)量。當(dāng)工作隊(duì)列已滿免绿,且已創(chuàng)建的線程數(shù)小于最大線程數(shù)時(shí),線程池會(huì)嘗試?yán)^續(xù)創(chuàng)建新線程來處理任務(wù)擦盾。
重要性:限制了線程池能夠同時(shí)處理的最大任務(wù)數(shù)嘲驾,有助于避免系統(tǒng)資源耗盡。
3.keepAliveTime(線程存活時(shí)間):
定義:當(dāng)線程數(shù)大于核心線程數(shù)時(shí)迹卢,多余的空閑線程在終止前等待新任務(wù)的最長(zhǎng)時(shí)間辽故。
重要性:有助于減少空閑線程的數(shù)量,從而節(jié)省系統(tǒng)資源腐碱。
4.unit(時(shí)間單位):
定義:keepAliveTime參數(shù)的時(shí)間單位誊垢,如秒(SECONDS)、毫秒(MILLISECONDS)等症见。
重要性:與keepAliveTime配合使用喂走,確保時(shí)間參數(shù)的準(zhǔn)確性。
5.workQueue(工作隊(duì)列):
定義:用于存放待執(zhí)行任務(wù)的阻塞隊(duì)列谋作。當(dāng)所有核心線程都在工作時(shí)芋肠,新任務(wù)會(huì)被添加到這個(gè)隊(duì)列中等待執(zhí)行。
重要性:決定了任務(wù)調(diào)度的順序和線程池的飽和策略遵蚜。常見的實(shí)現(xiàn)類有LinkedBlockingQueue帖池、ArrayBlockingQueue、SynchronousQueue等吭净。
6.threadFactory(線程工廠):
定義:用于創(chuàng)建新線程的工廠類睡汹,可以定制線程對(duì)象的創(chuàng)建,例如設(shè)置線程名字寂殉、是否是守護(hù)線程等囚巴。
重要性:提供了對(duì)線程創(chuàng)建過程的控制,有助于實(shí)現(xiàn)更復(fù)雜的線程池配置不撑。
7.handler(拒絕策略):
定義:當(dāng)線程池和工作隊(duì)列都滿了文兢,無法再處理新任務(wù)時(shí),會(huì)觸發(fā)拒絕策略焕檬。
重要性:確保了線程池在飽和狀態(tài)下的行為是可預(yù)測(cè)和可控的姆坚。常見的拒絕策略有AbortPolicy(直接拋出異常)、CallerRunsPolicy(調(diào)用者線程執(zhí)行)实愚、DiscardPolicy(丟棄任務(wù))和DiscardOldestPolicy(丟棄最老的任務(wù))等兼呵。
LinkedBlockingQueue兔辅、ArrayBlockingQueue、SynchronousQueue 都是 Java 中常用的阻塞隊(duì)列實(shí)現(xiàn)击喂,它們?cè)诰€程池等多線程場(chǎng)景中扮演著重要角色维苔,用于保存等待執(zhí)行的任務(wù)。以下是它們之間的主要區(qū)別:
1. 容量與存儲(chǔ)機(jī)制
LinkedBlockingQueue:
容量:可以選擇無界或有界懂昂。無界情況下介时,容量可以非常大,實(shí)際上是?Integer.MAX_VALUE凌彬。有界情況下沸柔,可以在創(chuàng)建隊(duì)列時(shí)指定容量。
存儲(chǔ)機(jī)制:基于鏈表的數(shù)據(jù)結(jié)構(gòu)铲敛,內(nèi)部維持著一個(gè)數(shù)據(jù)緩沖隊(duì)列(該隊(duì)列由鏈表構(gòu)成)褐澎。
ArrayBlockingQueue:
容量:有界,且容量在創(chuàng)建隊(duì)列時(shí)需要指定伐蒋,一旦設(shè)置就無法更改工三。
存儲(chǔ)機(jī)制:基于數(shù)組的數(shù)據(jù)結(jié)構(gòu),內(nèi)部維持著一個(gè)定長(zhǎng)數(shù)據(jù)緩沖隊(duì)列(該隊(duì)列由數(shù)組構(gòu)成)先鱼。
SynchronousQueue:
容量:無容量携冤,或者說其容量為1(但這里的1并不代表實(shí)際存儲(chǔ)的容量隐孽,而是指其操作特性)。
存儲(chǔ)機(jī)制:不真正存儲(chǔ)元素,每個(gè)插入操作必須等待相應(yīng)的刪除操作撬腾,反之亦然创泄。
2. 并發(fā)性能與鎖機(jī)制
LinkedBlockingQueue:
并發(fā)性能:通常表現(xiàn)較好野哭,尤其是在線程多揭芍、隊(duì)列長(zhǎng)度長(zhǎng)的情況下。
鎖機(jī)制:對(duì)生產(chǎn)者端和消費(fèi)者端分別采用了獨(dú)立的鎖來控制數(shù)據(jù)同步绷落,提高了并發(fā)性能姥闪。
ArrayBlockingQueue:
并發(fā)性能:一般,且在生產(chǎn)者放入數(shù)據(jù)和消費(fèi)者獲取數(shù)據(jù)時(shí)共用同一個(gè)鎖對(duì)象砌烁,這意味著兩者無法真正并行運(yùn)行筐喳。
鎖機(jī)制:基于?ReentrantLock?鎖和?Condition?條件變量實(shí)現(xiàn)線程安全。
SynchronousQueue:
并發(fā)性能:在特定場(chǎng)景下(如線程少函喉、隊(duì)列長(zhǎng)度短)表現(xiàn)穩(wěn)定且高效避归。
鎖機(jī)制:根據(jù)構(gòu)造時(shí)的公平性或非公平性選擇,使用公平鎖或非公平鎖管呵。
3. 使用場(chǎng)景
LinkedBlockingQueue:
適用于任務(wù)量不斷增加且無限制的場(chǎng)景梳毙,可以無限制地添加任務(wù)。
適用于高并發(fā)捐下、隊(duì)列長(zhǎng)度可能很長(zhǎng)的場(chǎng)景账锹。
ArrayBlockingQueue:
適用于任務(wù)量有限且已知的場(chǎng)景萌业,可以根據(jù)需求設(shè)置合理的容量。
適用于需要控制隊(duì)列大小奸柬,避免內(nèi)存占用過大的場(chǎng)景生年。
SynchronousQueue:
適用于任務(wù)執(zhí)行的過程需要嚴(yán)格的同步,任務(wù)的執(zhí)行和處理是一對(duì)一的關(guān)系廓奕。
適用于生產(chǎn)者-消費(fèi)者模型中抱婉,生產(chǎn)者線程和消費(fèi)者線程之間的直接傳遞,避免任務(wù)堆積桌粉。
4. 優(yōu)缺點(diǎn)總結(jié)
LinkedBlockingQueue:
優(yōu)點(diǎn):適用于任務(wù)量不斷增加的情況授段,可以無限制地添加任務(wù),適合使用在不限制任務(wù)數(shù)量的場(chǎng)景番甩。
缺點(diǎn):無固定容量可能導(dǎo)致內(nèi)存占用過大,需要注意內(nèi)存管理届搁。
ArrayBlockingQueue:
優(yōu)點(diǎn):適用于任務(wù)量有限且已知的情況缘薛,可以根據(jù)需求設(shè)置合理的容量,避免內(nèi)存占用過大卡睦。
缺點(diǎn):隊(duì)列容量固定宴胧,可能導(dǎo)致任務(wù)被丟棄,如果沒有設(shè)置合理的容量表锻,可能會(huì)導(dǎo)致任務(wù)阻塞恕齐。
SynchronousQueue:
優(yōu)點(diǎn):適用于任務(wù)執(zhí)行的過程需要嚴(yán)格的同步,任務(wù)的執(zhí)行和處理是一對(duì)一的關(guān)系瞬逊。
缺點(diǎn):沒有緩沖區(qū)显歧,如果沒有立即找到匹配的生產(chǎn)者或消費(fèi)者,插入和刪除操作都會(huì)被阻塞确镊。
4.java中常用的鎖
1. 樂觀鎖與悲觀鎖
樂觀鎖:認(rèn)為一個(gè)線程去拿數(shù)據(jù)的時(shí)候不會(huì)有其他線程對(duì)數(shù)據(jù)進(jìn)行更改士骤,所以不會(huì)上鎖。樂觀鎖的實(shí)現(xiàn)通常依賴于CAS(Compare-And-Swap)機(jī)制或版本號(hào)機(jī)制蕾域。在Java中拷肌,以Atomic開頭的包裝類(如AtomicBoolean、AtomicInteger旨巷、AtomicLong)就是樂觀鎖的一種實(shí)現(xiàn)巨缘。
悲觀鎖:認(rèn)為一個(gè)線程去拿數(shù)據(jù)時(shí)一定會(huì)有其他線程對(duì)數(shù)據(jù)進(jìn)行更改,所以一個(gè)線程在拿數(shù)據(jù)的時(shí)候都會(huì)順便加鎖采呐,這樣別的線程此時(shí)想拿這個(gè)數(shù)據(jù)就會(huì)阻塞若锁。Java中的synchronized關(guān)鍵字和Lock的實(shí)現(xiàn)類(如ReentrantLock)都是悲觀鎖的實(shí)現(xiàn)。
2. 公平鎖與非公平鎖
公平鎖:按照請(qǐng)求鎖的順序來獲取鎖斧吐,即“先來后到”拴清。這種鎖可以確保線程獲得鎖的順序是公平的靶病,但可能會(huì)降低并發(fā)性能。
非公平鎖:不保證獲取鎖的順序口予,即線程獲取鎖的順序可能與請(qǐng)求鎖的順序不一致娄周。這種鎖可以提高并發(fā)性能,但可能會(huì)導(dǎo)致某些線程長(zhǎng)時(shí)間等待沪停。
3. 可重入鎖與不可重入鎖
可重入鎖:同一個(gè)線程可以多次獲取同一把鎖煤辨,而不會(huì)發(fā)生死鎖。在Java中木张,ReentrantLock就是一個(gè)可重入鎖的實(shí)現(xiàn)众辨。
不可重入鎖:一個(gè)線程針對(duì)同一把鎖加鎖兩次,會(huì)發(fā)生死鎖舷礼。Java標(biāo)準(zhǔn)庫(kù)中并沒有直接提供不可重入鎖的實(shí)現(xiàn)鹃彻,但可以通過自定義鎖來模擬。
4. 獨(dú)享鎖與共享鎖
獨(dú)享鎖:只有一個(gè)線程可以訪問資源妻献,如Java中的synchronized關(guān)鍵字和ReentrantLock默認(rèn)都是獨(dú)享鎖蛛株。
共享鎖:允許多個(gè)線程同時(shí)讀取資源,但寫入時(shí)仍需獨(dú)占訪問育拨。Java中的ReadWriteLock接口及其實(shí)現(xiàn)類(如ReentrantReadWriteLock)就是共享鎖的一種實(shí)現(xiàn)谨履,其中讀鎖是共享鎖,寫鎖是獨(dú)享鎖熬丧。
5. 自旋鎖與適應(yīng)性自旋鎖
自旋鎖:嘗試獲取鎖的線程不會(huì)立即阻塞笋粟,而是采用循環(huán)的方式去嘗試獲取鎖。這種鎖的好處是減少線程上下文切換的消耗析蝴,但缺點(diǎn)是循環(huán)會(huì)消耗CPU害捕。在Java中,自旋鎖通常作為鎖升級(jí)過程中的一個(gè)階段(如從偏向鎖升級(jí)到輕量級(jí)鎖時(shí))闷畸。
適應(yīng)性自旋鎖:是自旋鎖的一種改進(jìn)吨艇,自旋的時(shí)間(次數(shù))不再固定,而是由前一次在同一個(gè)鎖上的自旋時(shí)間及鎖的擁有者的狀態(tài)來決定腾啥。這種鎖能夠更智能地適應(yīng)不同的場(chǎng)景东涡,提高并發(fā)性能。
6. 其他特殊鎖
偏向鎖:針對(duì)加鎖對(duì)象的一種優(yōu)化手段倘待,當(dāng)一個(gè)線程第一次訪問一個(gè)對(duì)象時(shí)疮跑,會(huì)將該對(duì)象設(shè)置為偏向自己的狀態(tài),這樣當(dāng)該線程再次訪問該對(duì)象時(shí)凸舵,就不需要再進(jìn)行加鎖操作了祖娘。這是Java 1.6中引入的一種鎖優(yōu)化機(jī)制。
輕量級(jí)鎖:在鎖升級(jí)過程中啊奄,如果鎖的競(jìng)爭(zhēng)不是很激烈渐苏,JVM會(huì)將鎖從偏向鎖升級(jí)為輕量級(jí)鎖掀潮。輕量級(jí)鎖的實(shí)現(xiàn)依賴于CAS機(jī)制和Mark Word中的鎖標(biāo)志位。
重量級(jí)鎖:如果鎖的競(jìng)爭(zhēng)非常激烈琼富,JVM會(huì)將鎖從輕量級(jí)鎖升級(jí)為重量級(jí)鎖仪吧。重量級(jí)鎖的實(shí)現(xiàn)依賴于操作系統(tǒng)的Mutex Lock(互斥鎖),并涉及線程上下文切換和內(nèi)核態(tài)與用戶態(tài)之間的轉(zhuǎn)換鞠眉,因此性能開銷較大薯鼠。
7. 其他常見鎖
Synchronized鎖:Java中最基本的鎖機(jī)制,基于對(duì)象的內(nèi)置監(jiān)視器(或稱為鎖)來實(shí)現(xiàn)線程同步械蹋。
ReentrantLock鎖:Java提供的可重入鎖出皇,具有與synchronized鎖相似的功能,但提供了更高的靈活性和擴(kuò)展性哗戈。
ReadWriteLock(讀寫鎖):允許多個(gè)線程同時(shí)讀取數(shù)據(jù)郊艘,但只允許一個(gè)線程寫入數(shù)據(jù)。讀寫鎖通常用于讀多寫少的場(chǎng)景唯咬。
Condition鎖:與鎖相關(guān)聯(lián)的條件對(duì)象纱注,允許線程在特定條件滿足時(shí)等待或被喚醒。Condition鎖通常與ReentrantLock結(jié)合使用副渴。
StampedLock鎖:Java 8中引入的一種樂觀鎖機(jī)制,提供了一種讀寫鎖的變體全度,允許樂觀讀取操作煮剧,從而提供更高的并發(fā)性能。
LockSupport鎖:一個(gè)線程阻塞工具将鸵,可以用于創(chuàng)建鎖和其他同步類的基本線程阻塞原語(yǔ)勉盅。它與每個(gè)線程都關(guān)聯(lián)了一個(gè)許可證,可以用于阻塞和解除阻塞線程顶掉。
Synchronized和volatile的區(qū)別
1.同步級(jí)別:volatile僅能用于變量級(jí)別草娜,而synchronized可以用于變量、方法或類級(jí)別痒筒。
2.可見性與原子性:volatile僅能保證變量的可見性和禁止指令重排宰闰,但不能保證原子性;而synchronized既能保證變量的可見性和原子性簿透,又能防止多個(gè)線程同時(shí)訪問共享資源導(dǎo)致的數(shù)據(jù)不一致問題移袍。
3.性能開銷:由于volatile的輕量級(jí)特性,其性能開銷通常小于synchronized老充。但是葡盗,在需要保證原子性的場(chǎng)景下,volatile可能無法滿足需求啡浊,此時(shí)需要使用synchronized或其他同步機(jī)制觅够。
4.使用場(chǎng)景:volatile適用于狀態(tài)標(biāo)記量胶背、雙重檢查等場(chǎng)景;而synchronized適用于對(duì)共享變量的訪問和修改喘先、對(duì)類實(shí)例化的構(gòu)造函數(shù)進(jìn)行同步等場(chǎng)景钳吟。
5.HasMap
Java為數(shù)據(jù)結(jié)構(gòu)中的映射定義了一個(gè)接口java.util.Map,此接口主要有四個(gè)常用的實(shí)現(xiàn)類苹祟,分別是HashMap砸抛、Hashtable、LinkedHashMap和TreeMap
(1) HashMap:它根據(jù)鍵的hashCode值存儲(chǔ)數(shù)據(jù)树枫,大多數(shù)情況下可以直接定位到它的值直焙,因而具有很快的訪問速度,但遍歷順序卻是不確定的砂轻。 HashMap最多只允許一條記錄的鍵為null奔誓,允許多條記錄的值為null。HashMap非線程安全搔涝,即任一時(shí)刻可以有多個(gè)線程同時(shí)寫HashMap厨喂,可能會(huì)導(dǎo)致數(shù)據(jù)的不一致。如果需要滿足線程安全庄呈,可以用 Collections的synchronizedMap方法使HashMap具有線程安全的能力蜕煌,或者使用ConcurrentHashMap。
(2) Hashtable:Hashtable是遺留類诬留,很多映射的常用功能與HashMap類似斜纪,不同的是它承自Dictionary類,并且是線程安全的文兑,任一時(shí)間只有一個(gè)線程能寫Hashtable盒刚,并發(fā)性不如ConcurrentHashMap,因?yàn)镃oncurrentHashMap引入了分段鎖绿贞。Hashtable不建議在新代碼中使用因块,不需要線程安全的場(chǎng)合可以用HashMap替換,需要線程安全的場(chǎng)合可以用ConcurrentHashMap替換籍铁。
(3) LinkedHashMap:LinkedHashMap是HashMap的一個(gè)子類涡上,保存了記錄的插入順序,在用Iterator遍歷LinkedHashMap時(shí)拒名,先得到的記錄肯定是先插入的吓懈,也可以在構(gòu)造時(shí)帶參數(shù),按照訪問次序排序靡狞。
(4) TreeMap:TreeMap實(shí)現(xiàn)SortedMap接口耻警,能夠把它保存的記錄根據(jù)鍵排序,默認(rèn)是按鍵值的升序排序,也可以指定排序的比較器甘穿,當(dāng)用Iterator遍歷TreeMap時(shí)腮恩,得到的記錄是排過序的。如果使用排序的映射温兼,建議使用TreeMap秸滴。在使用TreeMap時(shí),key必須實(shí)現(xiàn)Comparable接口或者在構(gòu)造TreeMap傳入自定義的Comparator募判,否則會(huì)在運(yùn)行時(shí)拋出java.lang.ClassCastException類型的異常荡含。
內(nèi)部實(shí)現(xiàn)(存儲(chǔ)結(jié)構(gòu)-字段)
從結(jié)構(gòu)實(shí)現(xiàn)來講,HashMap是數(shù)組+鏈表+紅黑樹(JDK1.8增加了紅黑樹部分)實(shí)現(xiàn)的届垫,如下如所示释液。
(1)HashMap類中有一個(gè)非常重要的字段,就是 Node[] table装处,即哈希桶數(shù)組误债,明顯它是一個(gè)Node的數(shù)組。
(2)HashMap就是使用哈希表來存儲(chǔ)的妄迁。哈希表為解決沖突寝蹈,可以采用開放地址法和鏈地址法等來解決問題,Java中HashMap采用了鏈地址法登淘。鏈地址法箫老,簡(jiǎn)單來說,就是數(shù)組加鏈表的結(jié)合黔州。在每個(gè)數(shù)組元素上都一個(gè)鏈表結(jié)構(gòu)耍鬓,當(dāng)數(shù)據(jù)被Hash后,得到數(shù)組下標(biāo)辩撑,把數(shù)據(jù)放在對(duì)應(yīng)下標(biāo)元素的鏈表上界斜。