Java基礎(chǔ)總結(jié)

??親們,作為程序員你可以不跳槽,但是不能不學(xué)習(xí),本文針對(duì)多份面試情況,總結(jié)了面試Android崗必問(wèn)的Java部分的基礎(chǔ),多維度分析了問(wèn)題的原理,使用,以及特點(diǎn),希望對(duì)正在面試或?qū)⒁嬖嚨哪銕?lái)一點(diǎn)幫助。如有疑問(wèn)可留言說(shuō)明。

HashMap,HashTable,ConcurrentHashMap的內(nèi)部實(shí)現(xiàn)方式都是什么?有什么區(qū)別?

HashMap

實(shí)現(xiàn)方式以及內(nèi)部原理

  • 底層數(shù)組+鏈表,HashMap基于哈希思想,實(shí)現(xiàn)對(duì)數(shù)據(jù)的讀寫。當(dāng)我們將鍵值對(duì)傳遞給put()方法時(shí),它調(diào)用鍵對(duì)象的hashCode()方法來(lái)計(jì)算hashcode,然后找到bucket位置來(lái)存儲(chǔ)值對(duì)象。當(dāng)獲取對(duì)象時(shí),通過(guò)鍵對(duì)象的equals()方法找到正確的鍵值對(duì),然后返回值對(duì)象。HashMap使用鏈表來(lái)解決碰撞問(wèn)題,當(dāng)發(fā)生碰撞時(shí),對(duì)象將會(huì)儲(chǔ)存在鏈表的下一個(gè)節(jié)點(diǎn)中。HashMap在每個(gè)鏈表節(jié)點(diǎn)中儲(chǔ)存鍵值對(duì)對(duì)象。當(dāng)兩個(gè)不同的鍵對(duì)象的hashcode相同時(shí),它們會(huì)儲(chǔ)存在同一個(gè)bucket位置的鏈表中,可通過(guò)鍵對(duì)象的equals()方法來(lái)找到鍵值對(duì)。如果鏈表大小超過(guò)閾值(TREEIFY_THRESHOLD,8),鏈表就會(huì)被改造為樹(shù)形結(jié)構(gòu)。

包含的屬性

    1. 容量(capacity)
    1. 初始化容量(initial capacity)
    1. size
    1. 負(fù)載因子(load factor)
    1. 負(fù)載極限(0 ~ 1)默認(rèn)負(fù)載極限是0.75。

特性

    1. 基于AbstractMap
    1. 可以存null鍵和null值,get方法為空無(wú)法判斷是鍵不存在還是值為null,可用containsKey()判斷。
    1. 初始size為16,擴(kuò)容newsize =oldsize*2,size是2的n次冪。
    1. 擴(kuò)容后原來(lái)數(shù)組元素會(huì)依次重新計(jì)算存放位置,并重新插入。
    1. Map中元素?cái)?shù)超過(guò)Entry數(shù)組的75%則觸發(fā)擴(kuò)容。
    1. 計(jì)算index方法:index=hash&(tab.length-1)等價(jià)于hash%(tab.length-1),但&預(yù)算效率高。
    1. 達(dá)到負(fù)載極限(size/capacity)會(huì)觸發(fā)rehashing(重新散列),也就是擴(kuò)容。
      • 7.1 負(fù)載極限越高,HashMap對(duì)象占用的內(nèi)存越小,但查詢效率會(huì)低(同一個(gè)空間里面的元素?cái)?shù)目就可能會(huì)增加,會(huì)增加查找的時(shí)間), hash碰撞會(huì)越頻繁。
      • 7.2 負(fù)載極限越低,查詢性能會(huì)提高,但是HashMap的內(nèi)存會(huì)增加
    1. 線程不安全
    1. 插入完數(shù)據(jù)在判斷是否擴(kuò)容,容易造成無(wú)效擴(kuò)容。
    1. 線程不安全是因?yàn)闊o(wú)鎖,因此使用效率高。
    1. 迭代器(Iterator)是fail-fast迭代器,其它線程改變了HashMap的結(jié)構(gòu)(增加或者移除元素),將會(huì)拋出ConcurrentModificationException,但迭代器本身的remove()方法移除元素則不會(huì)拋出ConcurrentModificationException異常。但這并不是一個(gè)一定發(fā)生的行為,要看JVM

HashTable

實(shí)現(xiàn)方式

  • 底層數(shù)組+鏈表

包含屬性

    1. 容量(capacity)
    1. 初始化容量(initial capacity)
    1. size
    1. 負(fù)載因子(load factor)
    1. 負(fù)載極限(0 ~ 1)默認(rèn)負(fù)載極限是0.75。

特性

    1. 基于Dictionary類
    1. k/v均不能為null
    1. 初始size為11,擴(kuò)容oldsize*2+1
    1. 計(jì)算index=(hash&0x7FFFFFFF)%tab.length
    1. 線程安全,但是效率低,因?yàn)槊看尾僮鲾?shù)據(jù)都會(huì)將整個(gè)hash表鎖住。
    1. jdk1.8之后也使用了fast-fail機(jī)制

ConcurrentHashMap

實(shí)現(xiàn)方式

  • JDK1.7 Segment + HashEntry
  • JDK1.8 Node + CAS + Synchronized

特性

    1. 線程安全,使用了鎖分段技術(shù)來(lái)保證線程安全的。
    • 1.1 數(shù)據(jù)分段存儲(chǔ),每段數(shù)據(jù)都有一把鎖,當(dāng)一個(gè)線程操作這段數(shù)據(jù)的時(shí)候,本段會(huì)鎖住,但是其他段不受影響,默認(rèn)是16段,諸如get、put、remove等常用操作只鎖住當(dāng)前需要用到的桶。這樣,原來(lái)只能一個(gè)線程進(jìn)入,現(xiàn)在卻能同時(shí)有16個(gè)寫線程執(zhí)行,并發(fā)性能的提升是顯而易見(jiàn)的。
    1. Map分為N個(gè)Segment(段),效率提升N倍,默認(rèn)提升16倍。并且讀操作是不加鎖的,因?yàn)镠ashEntry的value使用volatile修飾過(guò),可以保證數(shù)據(jù)讀取為最新數(shù)據(jù)。
    1. 允許多個(gè)修改并發(fā)進(jìn)行,因?yàn)槭褂昧随i分離技術(shù)。
    1. 例如size()方法,containsValue()方法需要跨Segment(段)操作,可能需要順序鎖定所有段,在順序釋放所有鎖。
    1. 段內(nèi)擴(kuò)容,無(wú)需整個(gè)Map擴(kuò)容,插入前擴(kuò)容,可防止無(wú)效擴(kuò)容。
    1. 比HashMap多了Segment,Segment是一個(gè)可重入鎖(Segment繼承了ReentrantLock)。

JDK1.7~1.8實(shí)現(xiàn)分析

  • put()方法實(shí)現(xiàn)(JDK1.7)
    當(dāng)執(zhí)行put方法插入數(shù)據(jù)時(shí),根據(jù)key的hash值,在Segment數(shù)組中找到相應(yīng)的位置,如果相應(yīng)位置的Segment還未初始化,則通過(guò)CAS進(jìn)行賦值,接著執(zhí)行Segment對(duì)象的put方法通過(guò)加鎖機(jī)制插入數(shù)據(jù).
    如線程A和線程B同時(shí)執(zhí)行相同Segment對(duì)象的put方法

      1. 線程A通過(guò)tryLock()獲取到鎖并將HashEntry對(duì)象插入相應(yīng)位置。
      1. 線程B獲取鎖失敗,執(zhí)行scanAndLockForPut(),在該方法中重復(fù)執(zhí)行tryLock()(多處理器下重復(fù)64次,單處理器下重復(fù)1次),重復(fù)次數(shù)達(dá)到上線則lock()掛起。
      1. A線程完成后調(diào)用unLock()并通知B線程開(kāi)始執(zhí)行。
  • size()方法實(shí)現(xiàn)(JDK1.7)
    背景:ConcurrentHashMap支持多線程并發(fā)插入數(shù)據(jù),因此計(jì)算元素時(shí)可能會(huì)出現(xiàn)不準(zhǔn)確情況。

    1. 不加鎖,連續(xù)計(jì)算每個(gè)Segment的元素個(gè)數(shù),最多計(jì)算3次,如相鄰兩次結(jié)果相同則返回。
    2. 如相鄰兩次結(jié)果不同,則給每一個(gè)Segment加鎖再計(jì)算。
  • put()方法實(shí)現(xiàn)(JDK1.8)

    1. 根據(jù)key的hash值,在Node數(shù)組找到對(duì)應(yīng)的位置,如果Node未初始化,則通過(guò)CAS插入相應(yīng)數(shù)據(jù)。
    2. 如果相應(yīng)位置的Node不為空,且當(dāng)前該節(jié)點(diǎn)不處于移動(dòng)狀態(tài),則對(duì)該節(jié)點(diǎn)加synchronized鎖,如果該節(jié)點(diǎn)的hash不小于0,則遍歷鏈表更新節(jié)點(diǎn)或插入新節(jié)點(diǎn);
    3. 如果該節(jié)點(diǎn)是TreeBin類型的節(jié)點(diǎn),說(shuō)明是紅黑樹(shù)結(jié)構(gòu),則通過(guò)putTreeVal方法往紅黑樹(shù)中插入節(jié)點(diǎn);
    4. 如果binCount不為0,說(shuō)明put操作對(duì)數(shù)據(jù)產(chǎn)生了影響,如果當(dāng)前鏈表的個(gè)數(shù)達(dá)到8個(gè),則通過(guò)treeifyBin方法轉(zhuǎn)化為紅黑樹(shù),如果oldVal不為空,說(shuō)明是一次更新操作,沒(méi)有對(duì)元素個(gè)數(shù)產(chǎn)生影響,則直接返回舊值;
    5. 如果插入的是一個(gè)新節(jié)點(diǎn),則執(zhí)行addCount()方法嘗試更新元素個(gè)數(shù)baseCount;

Java線程創(chuàng)建有幾種方式?分別是什么?這幾種創(chuàng)建方式的有啥不同?

    1. 繼承Thread,new繼承的Thread的子類創(chuàng)建線程對(duì)象,并通過(guò).start方式啟動(dòng)線程。
    1. 實(shí)現(xiàn)Runnable接口,并通過(guò)new Thread(“接口實(shí)現(xiàn)類”)
    1. 通過(guò)Callable和Future,實(shí)現(xiàn)Callable接口和call方法(該方法為線程的執(zhí)行體),通過(guò)FutureTask對(duì)象包裝Callable實(shí)現(xiàn)類對(duì)象,F(xiàn)utureTask作為Thread對(duì)象的target并啟動(dòng)新線程,最后通過(guò)new Thread("FutureTask對(duì)象")??烧{(diào)用FutureTask.get()阻塞線程并獲取線程執(zhí)行結(jié)束的返回值。

這三種創(chuàng)建線程的區(qū)別?

    1. 采用Runnable,Callable接口,線程類只實(shí)現(xiàn)了接口,同時(shí)可以繼承其他類。
    1. 接口實(shí)現(xiàn),代表多個(gè)線程共享一個(gè)target對(duì)象,適合多個(gè)相同線程處理同一份資源,可將代碼數(shù)據(jù)分開(kāi),能較好體現(xiàn)面向?qū)ο笏枷?/li>
    1. 通過(guò)接口實(shí)現(xiàn)的線程類,獲取當(dāng)前線程只能通過(guò)Thread.currentThread();

Synchronized和ReentantLock鎖內(nèi)部原理?

Synchronized
  • Java中每個(gè)對(duì)象都可作為鎖,線程視圖訪問(wèn)同步代碼時(shí),必須先獲取對(duì)象鎖,退出或拋異常時(shí)釋放鎖。

  • 原理

    1. 通過(guò)進(jìn)入/退出Monitor對(duì)象實(shí)現(xiàn)代碼塊同步和方法同步。
    1. 代碼塊同步:在編譯后將monitorenter指令插如同步代碼開(kāi)始處,將monitorexit指令插入同步代碼結(jié)束處,指令通過(guò)反編譯字節(jié)碼可以查看,執(zhí)行到monitorenter開(kāi)始獲取monitor所有權(quán),即獲得對(duì)象鎖。
    1. 方法同步:方法內(nèi)有ACC_synchronized標(biāo)記,線程執(zhí)行到該標(biāo)記,獲取對(duì)應(yīng)鎖,實(shí)現(xiàn)方法同步。
    1. 代碼塊/方法同步實(shí)現(xiàn)細(xì)節(jié)不同,但本質(zhì)均是對(duì)monitor監(jiān)視器的獲取,每個(gè)對(duì)象都有自己的monitor,在執(zhí)行同步代碼塊或同步方法時(shí)需要先獲取monitor才能執(zhí)行邏輯,沒(méi)有獲取到monitor的線程將會(huì)阻塞,并進(jìn)入同步隊(duì)列,狀態(tài)變?yōu)锽LOCKED,當(dāng)其他線程釋放monitor后,會(huì)通知同步隊(duì)列,重新獲取monitor。

舉例

    1. public synchronized void method1//方法同步,只能鎖住當(dāng)前對(duì)象,不同線程調(diào)用這一個(gè)對(duì)象會(huì)互斥,不同線程調(diào)用不同對(duì)象沒(méi)有效果。
    1. synchronized(this) //代碼塊同步,只鎖當(dāng)前對(duì)象。
    1. public synchronized static void method3//鎖住該類所有對(duì)象的,所有對(duì)象調(diào)用該方法均互斥。
    1. synchronized(Test.class)//鎖住Test類的所有對(duì)象,所有對(duì)象調(diào)用該代碼均互斥
    1. sysnchronized(o)//鎖住o對(duì)象。
ReentantLock
  • 一個(gè)可重入的互斥鎖,它具有與使用synchronized方法和語(yǔ)句所訪問(wèn)的隱式監(jiān)視器鎖相同的一些基本行為和語(yǔ)義。

  • 通過(guò)Lock接口鎖對(duì)象,Lock出現(xiàn)之前通過(guò)synchronized實(shí)現(xiàn)鎖功能,后來(lái)Lock提供了和synchronized類似的同步功能,只是使用的時(shí)候需要顯示的獲取和釋放鎖。

  • 缺點(diǎn)是缺少想synchronized那種隱式獲取釋放鎖的便捷性,但是獲得了手動(dòng)獲取釋放的操作性,同時(shí)可支持中斷獲取鎖,超時(shí)獲取鎖等功能。

  • 舉例

  ReentrantLock lock = new ReetrantLock();
  lock.lock() ;
  • 重入鎖
    • 當(dāng)一個(gè)線程獲取到一個(gè)對(duì)象的鎖后,再次請(qǐng)求該對(duì)象的鎖依然可以獲取到。(自己可以再次獲取自己的內(nèi)部鎖),Java內(nèi)置的Synchronized和ReetrantLock均是可重入鎖。
  • 公平鎖
    • CPU在調(diào)度線程中隨機(jī)選一個(gè)線程,隨機(jī)即無(wú)法保證先到先得(synchronized就是非公平鎖),會(huì)導(dǎo)致有些線程永遠(yuǎn)無(wú)法執(zhí)行,而公平鎖就用來(lái)解決這個(gè)問(wèn)題,保證線程按照時(shí)間的先后順序去執(zhí)行。
    • 非公平鎖效率會(huì)比較低,因?yàn)閮?nèi)部需要維護(hù)一個(gè)有序隊(duì)列。ReentrantLock即可實(shí)現(xiàn)公平鎖,通過(guò)構(gòu)造函數(shù)new ReentrantLock(true)即可。

Synchronized和ReentantLock鎖有什么區(qū)別?

    1. Lock是一個(gè)接口,synchronized是Java關(guān)鍵字,內(nèi)置語(yǔ)言實(shí)現(xiàn)。
    1. synchronized如果發(fā)生異常時(shí),會(huì)自動(dòng)釋放鎖,而Lock不會(huì)自動(dòng)釋放,如果不手動(dòng)釋放會(huì)造成死鎖。因此在finally塊中釋放。
    1. Lock可以操作等待線程中斷,通過(guò)lockInterruptibly()方法,synchronized不行。
    1. Lock可限時(shí),通過(guò)tryLock(long timeout, TimeUnit unit)指定等待的時(shí)間,超出這個(gè)時(shí)間以后會(huì)返回false并退出等待.
    1. Lock可以返回獲取鎖的狀態(tài),synchronized不行
    1. Lock可以提高多線程讀操作的效率。
    1. synchronized是非公平鎖,ReentrantLock可以設(shè)置為公平所/非公平鎖
    1. 在性能上來(lái)說(shuō),如果競(jìng)爭(zhēng)資源不激烈,兩者的性能是差不多的,而 當(dāng)競(jìng)爭(zhēng)資源非常激烈時(shí)(即有大量線程同時(shí)競(jìng)爭(zhēng)),此時(shí)ReentrantLock的性能要遠(yuǎn)遠(yuǎn)優(yōu)于synchronized 。所以說(shuō),在具體使用時(shí)要根據(jù)適當(dāng)情況選擇。而JDK1.6后這倆性能差不多了。

死鎖是怎么產(chǎn)生的?

    1. 互斥條件,一個(gè)資源只能被一個(gè)線程使用
    1. 請(qǐng)求與保持條件,一個(gè)線程因請(qǐng)求資源阻塞時(shí),對(duì)已獲得的資源保持不變。
    1. 不剝奪條件,線程使用的資源,在使用完之前,不能強(qiáng)行剝奪。
    1. 循環(huán)等待條件,若干線程形成首尾相接的循環(huán)等待資源關(guān)系。

死鎖的有哪幾種?

    1. 靜態(tài)鎖順序死鎖。ab兩個(gè)方法都需要獲得A鎖和B鎖,a方法獲取到了A鎖,等待B鎖,b方法獲取到了B鎖在等待A鎖??赏ㄟ^(guò)控制鎖的獲取順序解決該問(wèn)題。
    1. 動(dòng)態(tài)鎖順序死鎖。由于鎖是動(dòng)態(tài)傳入,因此循序顛倒會(huì)出現(xiàn)死鎖,可通過(guò)System.identityHashCode方法根據(jù)鎖對(duì)象的hashcode碼判斷順序。
    1. 協(xié)同對(duì)象死鎖。在一個(gè)有鎖的方法中調(diào)用了另一個(gè)對(duì)象有鎖的方法,容易造成死鎖,可以通過(guò)開(kāi)放調(diào)用。如果調(diào)用某個(gè)外部方法時(shí)不需要在有鎖的邏輯中調(diào)用,我們稱之為開(kāi)放調(diào)用。簡(jiǎn)單說(shuō)就是鎖只鎖需要加鎖的邏輯,其他邏輯無(wú)需再鎖邏輯中調(diào)用。

樂(lè)觀鎖和悲觀鎖有說(shuō)明區(qū)別?

    1. 悲觀鎖認(rèn)為每次操作數(shù)據(jù)時(shí)都會(huì)有人中途操作數(shù)據(jù),因此每次操作前都上鎖,并阻塞其他線程操作數(shù)據(jù)。直至操作完成。例如Java中的synchronized和ReentrantLock都為悲觀鎖。
    1. 樂(lè)觀鎖認(rèn)為每次操作數(shù)據(jù)時(shí)都不會(huì)有人中途操作數(shù)據(jù),所以每次都不會(huì)上鎖,但是每次更新前都會(huì)判斷下這個(gè)數(shù)據(jù)有沒(méi)有人改動(dòng)過(guò)。例如CAS算法機(jī)制。Java中的com.java.util.concurrent.atomic包下所有的原子變量類均使用了CAS。
    1. CAS用于多讀場(chǎng)景,即沖突很少的場(chǎng)景,這樣省去了鎖的開(kāi)銷,還增大了吞出量。多寫的場(chǎng)景,不建議使用CAS因?yàn)閷懖僮靼l(fā)生沖突,會(huì)導(dǎo)致死循環(huán)retry,反而降低了性能,這種建議使用悲觀鎖。

樂(lè)觀鎖有什么弊端?

    1. ABA問(wèn)題,線程1初次讀取變量的值為A,并且準(zhǔn)備賦值時(shí)還是A,那么就進(jìn)行賦值操作將值改為B,但是賦值前,其他線程有可能改成過(guò)C,然后又改回了A讓線程1誤認(rèn)為變量的值沒(méi)變。(可通過(guò)增加版本號(hào)解決ABA問(wèn)題,每次更新數(shù)據(jù)都將版本號(hào)+1,更新時(shí)需判斷原始數(shù)據(jù)和版本號(hào)均一致才更新)
    1. 更新數(shù)據(jù)長(zhǎng)時(shí)間不成功會(huì)導(dǎo)致循環(huán)次數(shù)增多,影響性能。
    1. 只能保證一個(gè)共享變量的原子操作。(可通過(guò)配合悲觀鎖,或者利用AtomicReference類保證將多個(gè)變量合并成一個(gè)共享變量操作)

并發(fā)編程的三大概念是什么?

    1. 原子性:即一個(gè)操作或多個(gè)操作要么全部執(zhí)行,要么就都不執(zhí)行,要么執(zhí)行過(guò)程中就不會(huì)被任何因素打斷。在Java中基本類型變量的讀取和賦值操作是原子性操作。
    1. 可見(jiàn)性:多個(gè)線程訪問(wèn)一個(gè)變量,當(dāng)一個(gè)線程改變了變量的值,其他線程立刻能看到修改后的值。在Java中通過(guò)volatile關(guān)鍵字保證可見(jiàn)性。
      • 2.1 通過(guò)volatile修飾過(guò)的變量能保證被修改后立即更新到主內(nèi)存。保證其他線程讀取到新值。
      • 2.2 通過(guò)synchronized和Lock也可以保證可見(jiàn)性,因?yàn)獒尫沛i會(huì)強(qiáng)制將變量新值更新到主內(nèi)存。
    1. 有序性:完全按照代碼的順序執(zhí)行。(處理器為提高程序運(yùn)行效率會(huì)將代碼優(yōu)化重新排序執(zhí)行。不一定保證代碼順序執(zhí)行,重排不影響單線程執(zhí)行,但可能影響多線程并發(fā)執(zhí)行)

Volatile有什么特性?用來(lái)做什么?

    1. 使用volatile修飾過(guò)的變量可保持不同線程對(duì)這個(gè)變量的可見(jiàn)性。
    1. 禁止進(jìn)行指令重排。
    1. volatile不能確保原子性
    1. volatile保證有序性
  • 使用舉例

    1. 狀態(tài)標(biāo)記量
  volatile boolean flag = false;
     //線程1
    while(!flag){
        doSomething();
    }
      //線程2
    public void setFlag() {
        flag = true;
    }
    1. 單例模式中的double check
 class Singleton {
    private volatile static Singleton instance = null;

    private Singleton() {

    }

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null)
                    instance = new Singleton();
            }
        }
        return instance;
    }
}
  • 分析
    以上代碼主要在于instance = new Singleton()這一句,這并非是一個(gè)原子操作,事實(shí)上在 JVM 中這句話大概做了下面 3 件事
    1. 給 instance 分配內(nèi)存
    1. 調(diào)用 Singleton 的構(gòu)造函數(shù)來(lái)初始化成員變量
    1. 將instance對(duì)象指向分配的內(nèi)存空間(執(zhí)行完這步 instance 就為非 null 了)
      但是在 JVM 的即時(shí)編譯器中存在指令重排序的優(yōu)化。也就是說(shuō)上面的第二步和第三步的順序是不能保證的,最終的執(zhí)行順序可能是 1-2-3 也可能是 1-3-2。如果是后者,則在 3 執(zhí)行完畢、2 未執(zhí)行之前,被線程二搶占了,這時(shí) instance 已經(jīng)是非 null 了(但卻沒(méi)有初始化),所以線程二會(huì)直接返回 instance,然后使用,然后順理成章地報(bào)錯(cuò)。

線程池有什么優(yōu)勢(shì)?為什么使用線程池?

    1. 降低系統(tǒng)資源消耗,通過(guò)重用已存在的線程可降低線程的創(chuàng)建和銷毀造成的消耗。
    1. 提高心痛響應(yīng)速度,有任務(wù)到達(dá),無(wú)需等待新線程創(chuàng)建即可執(zhí)行。
    1. 方便線程的并發(fā),管理,能有效的控制線程的創(chuàng)建,防止無(wú)限制創(chuàng)建線程,造成oom等不穩(wěn)定情況,線程池可進(jìn)行統(tǒng)一分配調(diào)優(yōu),提高資源使用率。
    1. 提供了定時(shí)定期以及可控線程數(shù)等功能的線程池??筛憬莸氖褂?。

線程池有幾種?分別是什么?都有什么區(qū)別?

  • 線程池有4種,分別是
  • 1. newFixedThreadPool
    線程數(shù)固定的線程池,最大線程數(shù)就是核心線程數(shù),沒(méi)有非核心線程,線程處于空閑狀態(tài)也不會(huì)回收,沒(méi)有超時(shí)機(jī)制,采用LinkedBlockingQueue。
  new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>())
  • 2. newCachedThreadPool
    通過(guò)Executors類的newCachedThreadPool()方法創(chuàng)建,該方法已經(jīng)設(shè)置了線程池的核心線程數(shù)和總線程數(shù),以及超時(shí)等待時(shí)間。
  newCachedThreadPool() {
     //核心線程數(shù)0,最大線程數(shù)MAX_VALUE,60秒鐘超時(shí)等待,
    //SynchronousQueue代表沒(méi)有等待隊(duì)列,每次都創(chuàng)建新線程。 線程空閑60秒后,線程將全部清空
     return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());
    }
  • 3. newScheduledThreadPool
    可用于定時(shí)執(zhí)行的任務(wù),初始化傳入核心線程數(shù),非核心線程數(shù)沒(méi)有限制,并且非核心線程空閑后立馬回收,可通過(guò)Executors.newScheduledThreadPool(int corePoolSize)創(chuàng)建ScheduledExecutorService 對(duì)象。
    - 3.1 通過(guò)ScheduledExecutorService.schedule(Runnable command, long delay, TimeUnit unit)設(shè)置延遲一定時(shí)間執(zhí)行Runnable。
    - 3.2 通過(guò)schedule(Callable callable, long delay, TimeUnit unit)設(shè)置延遲一定時(shí)間執(zhí)行Callable
    - 3.3 通過(guò)scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)延遲一定時(shí)間后固定一個(gè)時(shí)間執(zhí)行任務(wù)。執(zhí)行間隔為上一個(gè)任務(wù)執(zhí)行開(kāi)始到下一個(gè)任務(wù)執(zhí)行開(kāi)始。
    - 3.4 scheduleWithFixedDelay(Runnable command, long initialDelay, long delay,TimeUnit unit)和scheduleAtFixedRate方法類似,不同的是間隔計(jì)算從上一個(gè)任務(wù)執(zhí)行結(jié)束到下一個(gè)任務(wù)執(zhí)行開(kāi)始的計(jì)時(shí)。
  • 4. newSingleThreadExecutor
    只有一個(gè)核心線程,沒(méi)有非核心線程,線程忙碌時(shí)需排隊(duì)等待,通過(guò)newSingleThreadExecutor()初始化。

線程池內(nèi)線程數(shù)量分配多少合適?

    1. cpu密集類型任務(wù),線程數(shù)需盡可能少,可配置N+1線程的線程池
    1. IO操作遠(yuǎn)遠(yuǎn)高于cpu的任務(wù),可充分利用閑下來(lái)CPU,多創(chuàng)建線程,如2*N個(gè)線程。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容