(高頻問題)201-220 計(jì)算機(jī) Java后端 實(shí)習(xí) and 秋招 面試高頻問題匯總
200. 利用 Rand7() 構(gòu)造 Rand10():均勻隨機(jī)數(shù)生成
要利用已有的 rand7()
方法(生成 [1,7] 范圍內(nèi)的均勻隨機(jī)整數(shù))來實(shí)現(xiàn) rand10()
方法(生成 [1,10] 范圍內(nèi)的均勻隨機(jī)整數(shù)),核心在于構(gòu)造一個(gè)更大的、均勻分布的中間范圍,然后通過拒絕采樣法篩選出適用于目標(biāo)范圍的數(shù)值。
具體實(shí)現(xiàn)中,可以通過兩次調(diào)用 rand7()
來構(gòu)造一個(gè)更大的隨機(jī)數(shù)范圍。表達(dá)式 (rand7() - 1) * 7 + rand7()
能夠等概率地生成 [1,49] 范圍內(nèi)的整數(shù)。第一次 rand7() - 1
產(chǎn)生 [0,6] 之間的隨機(jī)數(shù),乘以 7 后得到 [0, 7, 14, 21, 28, 35, 42] 中的一個(gè)值,這代表了7個(gè)等概率的“基數(shù)”。第二次 rand7()
產(chǎn)生 [1,7] 之間的隨機(jī)數(shù),與基數(shù)相加后,就構(gòu)成了從 1 (0+1) 到 49 (42+7) 的均勻分布。
為了得到 [1,10] 的均勻分布,我們采用拒絕采樣。我們只接受生成的 num
在 [1,40] 范圍內(nèi)的值。如果 num
大于 40(即 41 到 49),則丟棄該值并重新生成,直到獲得一個(gè)在 [1,40] 區(qū)間內(nèi)的數(shù)。這樣做可以保證每個(gè)選中的數(shù)字(從1到40)出現(xiàn)的概率是相等的。最后,通過 num % 10 + 1
的操作,可以將 [1,40] 范圍內(nèi)的數(shù)映射到 [1,10] 范圍內(nèi)的數(shù),且保持均勻性。例如,1, 11, 21, 31 都會(huì)映射到 1;而 10, 20, 30, 40 都會(huì)映射到 10。
201. 重放攻擊的防御策略
重放攻擊(Replay Attack)是一種網(wǎng)絡(luò)攻擊手段,攻擊者會(huì)截獲合法的網(wǎng)絡(luò)通信數(shù)據(jù)包,并在稍后重新發(fā)送這些數(shù)據(jù)包給接收方,以達(dá)到欺騙系統(tǒng)、獲取未授權(quán)訪問或重復(fù)執(zhí)行操作的目的。攻擊者通常無需破解數(shù)據(jù)包內(nèi)容,僅利用其重放特性。
為有效抵御重放攻擊,常用的防御機(jī)制包括:
使用時(shí)間戳(Timestamp):在每個(gè)傳輸?shù)臄?shù)據(jù)包中嵌入當(dāng)前的時(shí)間戳。接收方在收到數(shù)據(jù)包后,會(huì)校驗(yàn)時(shí)間戳是否在其預(yù)設(shè)的有效時(shí)間窗口內(nèi)。若時(shí)間戳過舊或與當(dāng)前時(shí)間差異過大,則判定為潛在的重放數(shù)據(jù)包并予以丟棄。這種方法能有效防止舊數(shù)據(jù)包的重放,但其挑戰(zhàn)在于需要通信雙方維持較為精確的時(shí)間同步,并且時(shí)間戳的校驗(yàn)與管理會(huì)帶來一定的處理開銷。
使用序列號(hào)或隨機(jī)數(shù)(Nonce/Sequence Number):在通信會(huì)話的每個(gè)數(shù)據(jù)包中包含一個(gè)唯一的、單調(diào)遞增的序列號(hào),或者一個(gè)一次性的隨機(jī)數(shù) (Nonce)。接收方會(huì)維護(hù)一個(gè)已接收序列號(hào)的記錄或期望的下一個(gè)序列號(hào)(對(duì)于序列號(hào)機(jī)制),或者一個(gè)已使用的 Nonce 集合(對(duì)于 Nonce 機(jī)制)。若收到的數(shù)據(jù)包序列號(hào)重復(fù)、不符合預(yù)期順序,或 Nonce已被使用,則視為重放攻擊。這種方法實(shí)現(xiàn)相對(duì)簡(jiǎn)單且有效,但挑戰(zhàn)在于序列號(hào)或 Nonce 的生成、同步和管理,尤其是在分布式或高并發(fā)環(huán)境下。
202. Java 進(jìn)程 CPU 占用率飆升的排查與定位方法
當(dāng) Java 進(jìn)程出現(xiàn) CPU 占用率異常飆升時(shí),可采用以下步驟和工具進(jìn)行定位:
首先,在服務(wù)器層面,可以使用 Linux 系統(tǒng)自帶的命令進(jìn)行初步排查。top
命令能夠?qū)崟r(shí)顯示系統(tǒng)中各個(gè)進(jìn)程的資源占用情況,包括 CPU 使用率、內(nèi)存使用等,通過 Shift + P
可以按 CPU 使用率排序,快速找出消耗 CPU 最多的 Java 進(jìn)程ID(PID)。另外,ps -eo pid,ppid,cmd,%mem,%cpu --sort=-%cpu
命令也可以按 CPU 使用率降序顯示進(jìn)程信息。
在定位到具體的 Java 進(jìn)程后,可以進(jìn)一步使用 JDK 提供的工具進(jìn)行深入分析。jps
命令用于列出當(dāng)前系統(tǒng)中所有 Java 進(jìn)程及其 PID,方便確認(rèn)目標(biāo)進(jìn)程。jstack <PID>
命令則非常關(guān)鍵,它可以打印出指定 Java 進(jìn)程內(nèi)所有線程的堆棧跟蹤信息。通過分析線程堆棧,可以找出哪些線程正在執(zhí)行、是否處于死鎖狀態(tài),或者哪個(gè)方法調(diào)用消耗了大量 CPU 時(shí)間。通常,會(huì)多次執(zhí)行 jstack
,對(duì)比不同時(shí)間點(diǎn)的線程狀態(tài),定位繁忙的線程。此外,jstat
可用于監(jiān)控 JVM 的各類運(yùn)行時(shí)數(shù)據(jù),如 GC 活動(dòng)、類加載等。如果懷疑是內(nèi)存問題間接導(dǎo)致 CPU 升高(例如頻繁 GC),jmap
命令可以生成堆轉(zhuǎn)儲(chǔ)快照(heap dump),后續(xù)可使用 MAT (Memory Analyzer Tool) 等工具進(jìn)行分析。
203. 雙重檢查鎖定單例模式中 volatile
關(guān)鍵字的必要性分析
在雙重檢查鎖定(Double-Checked Locking)實(shí)現(xiàn)的單例模式中,volatile
關(guān)鍵字對(duì)于保證線程安全至關(guān)重要。其必要性主要體現(xiàn)在防止指令重排序?qū)е碌某跏蓟瘑栴}。
考慮以下典型的雙重檢查鎖定代碼片段:
// instance 變量需要被 volatile 修飾 private static volatile Singleton instance; public static Singleton getInstance() { if (instance == null) { // 第一次檢查 synchronized (Singleton.class) { if (instance == null) { // 第二次檢查 instance = new Singleton(); // 關(guān)鍵賦值操作 } } } return instance; }
問題出在 instance = new Singleton();
這一行。在 JVM 中,對(duì)象的創(chuàng)建并非原子操作,大致可以分解為以下三個(gè)步驟:
- 為
Singleton
實(shí)例分配內(nèi)存空間。 - 調(diào)用
Singleton
的構(gòu)造函數(shù),初始化成員字段。 - 將
instance
引用指向分配的內(nèi)存地址。
如果沒有 volatile
修飾 instance
變量,編譯器或處理器可能會(huì)對(duì)上述步驟進(jìn)行指令重排序。例如,實(shí)際執(zhí)行順序可能變成 1 -> 3 -> 2。在這種情況下,線程 A 執(zhí)行到步驟 3,instance
引用已經(jīng)指向了內(nèi)存地址,不再是 null
。但此時(shí)對(duì)象的初始化(步驟 2)可能尚未完成。如果線程 B 在此刻進(jìn)入第一個(gè) if (instance == null)
判斷,它會(huì)發(fā)現(xiàn) instance
不為 null
,從而直接返回一個(gè)尚未完全初始化的 instance
對(duì)象,后續(xù)使用該對(duì)象就可能引發(fā)錯(cuò)誤。
volatile
關(guān)鍵字通過其內(nèi)存屏障作用,可以禁止特定類型的指令重排序,確保了對(duì)象初始化的有序性 (具體來說,它保證了在將引用賦值給 instance
之前,對(duì)象的構(gòu)造函數(shù)一定已經(jīng)執(zhí)行完畢并完成了所有成員變量的初始化),同時(shí)也保證了 instance
變量在多線程之間的可見性。因此,volatile
在此場(chǎng)景下是確保單例模式線程安全的關(guān)鍵。
204. Java 應(yīng)用響應(yīng)緩慢或卡頓的線上排查思路
當(dāng)線上 Java 應(yīng)用程序出現(xiàn)運(yùn)行卡頓、響應(yīng)延遲增長(zhǎng)等不符合預(yù)期的情況時(shí),通常需要一套系統(tǒng)性的排查思路來定位問題根源。
首先,應(yīng)全面檢查服務(wù)器的系統(tǒng)資源使用狀況。使用 top
或 htop
命令監(jiān)控 CPU 使用率,若 CPU 持續(xù)高位運(yùn)行,可能指示計(jì)算密集型任務(wù)或死循環(huán)。通過 free -m
或 vmstat
查看內(nèi)存使用情況,高內(nèi)存占用可能指向內(nèi)存泄漏或需要優(yōu)化內(nèi)存分配策略。同時(shí),利用 iostat
關(guān)注磁盤 I/O,高 I/O 負(fù)載可能意味著磁盤讀寫瓶頸。
其次,深入分析 Java 應(yīng)用程序本身的線程活動(dòng)。通過 jstack <PID>
命令獲取 Java 進(jìn)程的線程堆棧信息,仔細(xì)分析是否存在死鎖、鎖競(jìng)爭(zhēng)激烈或長(zhǎng)時(shí)間運(yùn)行的線程??梢远啻巫ト《褩_M(jìn)行對(duì)比,找出持續(xù)占用 CPU 的熱點(diǎn)代碼。圖形化工具如 JConsole 或 VisualVM 也能直觀展示線程狀態(tài)和 CPU 消耗。
接下來,重點(diǎn)排查垃圾回收(GC)行為。分析 GC 日志(通過 -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:gc.log
等參數(shù)開啟),關(guān)注 GC 的頻率(尤其是 Full GC)和單次停頓時(shí)間。jstat -gcutil <PID> <interval>
命令可以實(shí)時(shí)監(jiān)控 GC 分代變化、GC 次數(shù)和耗時(shí)。頻繁或耗時(shí)過長(zhǎng)的 GC 是導(dǎo)致應(yīng)用卡頓的常見原因,可能需要調(diào)整堆大小、GC 策略或排查內(nèi)存泄漏。
同時(shí),審查應(yīng)用程序日志是必不可少的環(huán)節(jié)。仔細(xì)檢查應(yīng)用輸出的日志文件,尋找異常堆棧、錯(cuò)誤信息或處理緩慢的業(yè)務(wù)邏輯記錄,這些往往能直接或間接指向問題所在。
最后,如果應(yīng)用與數(shù)據(jù)庫交互頻繁,還需評(píng)估數(shù)據(jù)庫的性能表現(xiàn)。檢查慢查詢?nèi)罩荆治鰯?shù)據(jù)庫連接池狀態(tài),確認(rèn)是否存在數(shù)據(jù)庫瓶頸或 SQL 優(yōu)化空間。
205. 通過 Java GC 日志判斷應(yīng)用性能及預(yù)期符合度
通過分析 Java 的垃圾回收(GC)日志,可以有效地判斷應(yīng)用程序是否存在性能卡頓以及其運(yùn)行狀態(tài)是否符合預(yù)期。關(guān)鍵考察點(diǎn)包括:
GC 停頓時(shí)間(Pause Time):GC 日志會(huì)記錄每次 GC 事件造成的應(yīng)用停頓時(shí)間。例如,在 2024-08-04T12:00:00.123+0000: 123.456: [GC (Allocation Failure) [PSYoungGen: 2048K->256K(6144K)] 2048K->256K(19840K), 0.0056780 secs] [Times: user=0.02 sys=0.00, real=0.01 secs]
這樣的日志中,0.0056780 secs
(或者更準(zhǔn)確地看 real=0.01 secs
,代表實(shí)際停頓時(shí)間) 即表示該次 GC 的停頓時(shí)間。需要關(guān)注單次停頓時(shí)間是否過長(zhǎng),以及在特定時(shí)間窗口內(nèi)(如1分鐘)累積的總停頓時(shí)間。如果總停頓時(shí)間占比過高,例如在1分鐘內(nèi)累積停頓超過幾百毫秒甚至數(shù)秒,則表明 GC 對(duì)應(yīng)用吞吐量和響應(yīng)時(shí)間產(chǎn)生了顯著負(fù)面影響。
GC 頻率(Frequency):頻繁的 GC,特別是 Full GC,會(huì)導(dǎo)致應(yīng)用程序頻繁停頓。通過統(tǒng)計(jì)單位時(shí)間內(nèi) Minor GC 和 Full GC 的發(fā)生次數(shù),可以評(píng)估內(nèi)存分配壓力和老年代的健康狀況。GC 日志中通常會(huì)記錄 GC 的觸發(fā)原因,如 Allocation Failure
(年輕代空間不足導(dǎo)致 Minor GC)或 Ergonomics
(JVM 根據(jù)當(dāng)前堆狀況自動(dòng)觸發(fā) Full GC)、System.gc()
(顯式調(diào)用)。若 Allocation Failure
頻繁出現(xiàn),可能意味著對(duì)象創(chuàng)建速率過快或 Eden 區(qū)設(shè)置不當(dāng)。
GC 類型(Type):GC 日志會(huì)明確標(biāo)識(shí) Minor GC(通常標(biāo)記為 [GC ...]
或針對(duì)特定年輕代收集器的名稱如 [PSYoungGen ...]
)和 Full GC(標(biāo)記為 [Full GC ...]
)。Full GC 通常涉及整個(gè)堆的回收,停頓時(shí)間遠(yuǎn)長(zhǎng)于 Minor GC,因此應(yīng)重點(diǎn)關(guān)注 Full GC 的頻率和耗時(shí)。
堆內(nèi)存使用情況(Heap Usage):GC 日志詳細(xì)記錄了每次 GC 前后堆內(nèi)各區(qū)域(如年輕代、老年代)以及整個(gè)堆內(nèi)存的使用量變化。在上述示例日志 [PSYoungGen: 2048K->256K(6144K)] 2048K->256K(19840K)
中:
[PSYoungGen: 2048K->256K(6144K)]
表示:年輕代(PSYoungGen)在此次 GC 前使用了 2048K 內(nèi)存,GC 后降至 256K,其總大小為 6144K。2048K->256K(19840K)
表示:整個(gè)堆(包括年輕代和老年代)在此次 GC 前總共使用了 2048K 內(nèi)存,GC 后降至 256K,整個(gè)堆的總大小為 19840K。 通過觀察 GC 后內(nèi)存是否有效下降,可以判斷內(nèi)存回收效果;若 Full GC 后老年代內(nèi)存依然居高不下,可能存在內(nèi)存泄漏。
為了更高效地分析,可以借助 GC 日志分析工具,如 GCViewer 或 GCeasy。這些工具能將原始日志數(shù)據(jù)可視化,生成圖表和報(bào)告,幫助快速定位 GC 瓶頸。
206. 阻塞式I/O (BIO) 服務(wù)器:連接數(shù)與線程數(shù)的關(guān)系
在基于同步阻塞I/O (BIO) 模型實(shí)現(xiàn)的服務(wù)器中,其典型的網(wǎng)絡(luò)服務(wù)模式是為每一個(gè)客戶端連接分配一個(gè)獨(dú)立的線程進(jìn)行處理。這種模式下,主線程(或稱為Acceptor線程)負(fù)責(zé)監(jiān)聽并接受新的客戶端連接請(qǐng)求。
當(dāng)一個(gè)新的連接成功建立后,為了不阻塞主線程繼續(xù)接受其他連接,服務(wù)器通常會(huì)創(chuàng)建一個(gè)新的處理線程專門負(fù)責(zé)該連接上的數(shù)據(jù)讀取、業(yè)務(wù)處理和數(shù)據(jù)寫入。因此,如果此時(shí)服務(wù)器建立了100個(gè)客戶端連接,那么除了一個(gè)負(fù)責(zé)接收新連接的Acceptor線程外,還會(huì)額外創(chuàng)建100個(gè)用于處理這些已建立連接的線程。所以,總共會(huì)有 1 (Acceptor) + 100 (Handler) = 101 個(gè)線程在運(yùn)行。這種模型的缺點(diǎn)是,如果連接被建立后長(zhǎng)時(shí)間沒有數(shù)據(jù)交互,對(duì)應(yīng)的處理線程也會(huì)處于阻塞等待狀態(tài),造成線程資源的浪費(fèi)。
207. 非阻塞式I/O (NIO) 服務(wù)器:連接數(shù)與線程數(shù)的關(guān)系及Selector機(jī)制
與BIO模型不同,非阻塞I/O (NIO) 模型采用多路復(fù)用 (Multiplexing) 技術(shù),允許服務(wù)器使用少量線程處理大量并發(fā)連接。其核心組件是Selector (選擇器),它能夠同時(shí)監(jiān)控多個(gè)通道 (Channel) 上的I/O事件(如連接就緒、數(shù)據(jù)可讀、數(shù)據(jù)可寫等)。
當(dāng)服務(wù)器采用NIO模型時(shí),即使建立了100個(gè)客戶端連接,也不需要為每個(gè)連接都創(chuàng)建一個(gè)獨(dú)立的線程。通常,服務(wù)器會(huì)啟動(dòng)一個(gè)或少數(shù)幾個(gè)專門的I/O線程(通常稱為Reactor線程)來運(yùn)行Selector。這個(gè)Selector會(huì)監(jiān)聽所有注冊(cè)給它的Channel。當(dāng)任何一個(gè)Channel上發(fā)生I/O事件時(shí)(例如,一個(gè)新的客戶端連接請(qǐng)求到達(dá),或者某個(gè)已連接的客戶端發(fā)送了數(shù)據(jù)),Selector會(huì)被喚醒,相應(yīng)的I/O線程則可以獲取到這些就緒的事件,并進(jìn)行處理。對(duì)于連接建立事件,服務(wù)器會(huì)接受連接并將新的Channel注冊(cè)到Selector上;對(duì)于數(shù)據(jù)讀寫事件,I/O線程會(huì)讀取數(shù)據(jù),然后可以將業(yè)務(wù)處理分發(fā)給后端的業(yè)務(wù)線程池。
因此,在NIO模型下,處理100個(gè)連接的I/O線程數(shù)量通常是固定的,且遠(yuǎn)小于連接數(shù),例如CPU核心數(shù)個(gè)線程。實(shí)際的線程總數(shù)還會(huì)包括用于執(zhí)行耗時(shí)業(yè)務(wù)邏輯的線程池中的線程,但負(fù)責(zé)網(wǎng)絡(luò)I/O本身的線程數(shù)量得到了顯著優(yōu)化。
208. 處理器核心類型(大核/小核)與線程技術(shù)(物理/邏輯/超線程)解析
現(xiàn)代處理器為了平衡性能與功耗,常采用多種核心設(shè)計(jì)和線程技術(shù)。
大核與小核:
大核 (Big Core) 通常設(shè)計(jì)有更強(qiáng)的單核計(jì)算能力和更復(fù)雜的指令流水線,適合處理計(jì)算密集型和對(duì)性能要求高的任務(wù),但其功耗也相對(duì)較高。小核 (Little Core) 則側(cè)重于能效,其計(jì)算能力相對(duì)較弱,但功耗顯著低于大核,適合處理后臺(tái)任務(wù)、輕量級(jí)應(yīng)用或在系統(tǒng)負(fù)載不高時(shí)維持基本運(yùn)行。大小核架構(gòu) (Big.LITTLE Architecture) 或類似混合架構(gòu)將這兩種核心集成在同一處理器中,操作系統(tǒng)通過動(dòng)態(tài)調(diào)度,將高負(fù)載任務(wù)分配給大核執(zhí)行,低負(fù)載或后臺(tái)任務(wù)則交由小核處理,以實(shí)現(xiàn)性能與功耗的最佳平衡。大核和小核均屬于物理核心。
物理核心、邏輯核心與超線程:
物理核心 (Physical Core) 是處理器芯片上實(shí)際存在的、獨(dú)立的中央處理單元。每個(gè)物理核心都具備完整的執(zhí)行單元、寄存器等。超線程技術(shù) (Hyper-Threading,Intel的技術(shù)名稱,AMD有類似SMT技術(shù)) 是一種允許單個(gè)物理核心模擬出兩個(gè)或多個(gè)邏輯核心 (Logical Core) 的技術(shù)。從操作系統(tǒng)的視角來看,每個(gè)邏輯核心都表現(xiàn)為一個(gè)獨(dú)立的處理單元,可以被分配和調(diào)度任務(wù)。操作系統(tǒng)在啟動(dòng)時(shí)會(huì)檢測(cè)到處理器提供的所有邏輯核心數(shù)量,并基于這些邏輯核心進(jìn)行任務(wù)調(diào)度。雖然操作系統(tǒng)主要與邏輯核心交互,但現(xiàn)代操作系統(tǒng)也能夠感知物理核心的拓?fù)浣Y(jié)構(gòu),并可能利用這些信息進(jìn)行更優(yōu)化的調(diào)度,例如盡量將關(guān)聯(lián)不大的任務(wù)分散到不同的物理核心上,以減少資源競(jìng)爭(zhēng)。
209. 負(fù)載均衡場(chǎng)景下客戶端長(zhǎng)連接池的挑戰(zhàn)與缺點(diǎn)
在客戶端使用長(zhǎng)連接池訪問經(jīng)過負(fù)載均衡器(Load Balancer, LB)代理的后端服務(wù)集群時(shí),雖然長(zhǎng)連接可以減少連接建立的開銷,但也可能引入一系列問題:
負(fù)載不均 (Uneven Load Distribution) 是一個(gè)核心問題。負(fù)載均衡器通常在建立新連接時(shí)根據(jù)其策略(如輪詢、最少連接數(shù)等)將請(qǐng)求分發(fā)到不同的后端服務(wù)實(shí)例。然而,客戶端一旦與某個(gè)后端服務(wù)實(shí)例建立了長(zhǎng)連接,后續(xù)通過該連接的所有請(qǐng)求都會(huì)固定發(fā)送到此實(shí)例,負(fù)載均衡器無法對(duì)這些后續(xù)請(qǐng)求進(jìn)行再次分發(fā)。這可能導(dǎo)致某些后端服務(wù)實(shí)例因承載了過多的長(zhǎng)連接而過載,而其他實(shí)例則相對(duì)空閑。
連接滯留 (Connection Staleness):長(zhǎng)連接長(zhǎng)時(shí)間處于空閑狀態(tài)后,可能因?yàn)榫W(wǎng)絡(luò)設(shè)備(如防火墻、NAT網(wǎng)關(guān))的超時(shí)策略或服務(wù)器端的意外重啟而變得無效或“死亡”,但客戶端連接池對(duì)此并不知情。當(dāng)客戶端嘗試復(fù)用這些失效連接時(shí),會(huì)導(dǎo)致請(qǐng)求失敗,影響應(yīng)用的可用性。
資源消耗 (Resource Consumption):每個(gè)長(zhǎng)連接都會(huì)持續(xù)占用客戶端和服務(wù)器端的內(nèi)存、文件描述符等系統(tǒng)資源。如果連接池維護(hù)了大量不活躍的長(zhǎng)連接,會(huì)造成不必要的資源浪費(fèi)。
連接數(shù)限制 (Connection Limits):服務(wù)器通常對(duì)單個(gè)客戶端或總體的并發(fā)連接數(shù)設(shè)有上限。大量長(zhǎng)連接,尤其是在多客戶端場(chǎng)景下,可能迅速耗盡服務(wù)器的可用連接數(shù)配額,導(dǎo)致新的連接請(qǐng)求被拒絕。
維護(hù)和更新挑戰(zhàn) (Maintenance and Update Challenges):當(dāng)需要對(duì)后端服務(wù)實(shí)例進(jìn)行維護(hù)、更新或縮容時(shí),長(zhǎng)連接的存在會(huì)使這些操作變得復(fù)雜。例如,要下線一個(gè)服務(wù)實(shí)例,必須妥善處理其上已建立的長(zhǎng)連接,否則可能導(dǎo)致服務(wù)中斷。如果強(qiáng)制斷開,客戶端需要有相應(yīng)的重連和容錯(cuò)機(jī)制。
210. 連接池的典型位置:調(diào)用方(客戶端)的實(shí)踐
連接池(Connection Pool)這一機(jī)制,通常部署在服務(wù)的調(diào)用方,也就是客戶端一側(cè)。其核心目的是管理客戶端與服務(wù)器之間的網(wǎng)絡(luò)連接,以提高通信效率和系統(tǒng)性能。
當(dāng)一個(gè)應(yīng)用程序(作為客戶端)需要頻繁地與另一個(gè)服務(wù)(如數(shù)據(jù)庫、遠(yuǎn)程API服務(wù))進(jìn)行通信時(shí),如果每次請(qǐng)求都重新建立TCP連接,并在請(qǐng)求結(jié)束后關(guān)閉連接,將會(huì)帶來顯著的開銷。這包括TCP三次握手建立連接的延遲和資源消耗,以及四次揮手關(guān)閉連接的過程。連接池通過預(yù)先創(chuàng)建并維護(hù)一定數(shù)量的連接,使得客戶端在需要發(fā)送請(qǐng)求時(shí),可以直接從池中獲取一個(gè)已經(jīng)建立好的空閑連接,使用完畢后將其歸還給池中,而不是直接關(guān)閉。這樣避免了每次請(qǐng)求都建立和關(guān)閉連接的開銷,提高了連接的復(fù)用率,顯著減少了請(qǐng)求延遲,提升了應(yīng)用的整體性能和吞吐量。
例如,一個(gè)Web應(yīng)用在訪問數(shù)據(jù)庫時(shí),會(huì)在Web應(yīng)用內(nèi)部(調(diào)用方)維護(hù)一個(gè)數(shù)據(jù)庫連接池。同樣,一個(gè)微服務(wù)A在調(diào)用微服務(wù)B時(shí),微服務(wù)A(調(diào)用方)可以針對(duì)到微服務(wù)B的HTTP請(qǐng)求維護(hù)一個(gè)HTTP連接池。
211. Java 中通過代碼精確控制 GC 行為:觸發(fā)特定次數(shù)的 Young GC 與 Full GC
要在 Java 程序中精確地觸發(fā)特定序列的垃圾回收(例如,兩次 Young GC,然后一次 Full GC,接著再兩次 Young GC),需要精心配置 JVM 參數(shù)并結(jié)合特定的對(duì)象分配和釋放策略。直接且穩(wěn)定地控制 GC 的確切發(fā)生時(shí)機(jī)是困難的,因?yàn)?GC 的行為受到多種因素影響,但可以通過以下方法盡可能地接近目標(biāo)。
首先,配置合適的 JVM 啟動(dòng)參數(shù)至關(guān)重要。例如,通過 -Xms
(初始堆大?。┖?-Xmx
(最大堆大?。┰O(shè)置一個(gè)固定的堆內(nèi)存,通過 -Xmn
設(shè)置一個(gè)相對(duì)較小的新生代大小,以便更容易填滿并觸發(fā) Young GC。使用 -XX:+PrintGCDet
可以觀察 GC 的詳細(xì)日志,幫助驗(yàn)證 GC行為。為了更可控,可以指定使用 (串行收集器),它的行為相對(duì)簡(jiǎn)單和可預(yù)測(cè)。
剩余60%內(nèi)容,訂閱專欄后可繼續(xù)查看/也可單篇購買
曾獲多國(guó)內(nèi)大廠的 ssp 秋招 offer,且是Java5年的沉淀老兵(不是)。專注后端高頻面試與八股知識(shí)點(diǎn),內(nèi)容系統(tǒng)詳實(shí),覆蓋約 30 萬字面試真題解析、近 400 個(gè)熱點(diǎn)問題(包含大量場(chǎng)景題),60 萬字后端核心知識(shí)(含計(jì)網(wǎng)、操作系統(tǒng)、數(shù)據(jù)庫、性能調(diào)優(yōu)等)。同時(shí)提供簡(jiǎn)歷優(yōu)化、HR 問題應(yīng)對(duì)、自我介紹等通用能力??紤]到歷史格式混亂、質(zhì)量較低、也在本地積累了大量資料,故準(zhǔn)備從頭重構(gòu)專欄全部?jī)?nèi)容