<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          今年后端爆了???

          共 7895字,需瀏覽 16分鐘

           ·

          2024-04-29 14:04

          大家好,我是二哥呀。

          每次登錄牛客,看到最多的就是各種 Java 后端崗位的喜訊,美團(tuán) OC了、快手 OC 了、就連騰訊 OC 的都是 Java 崗,我懷疑牛客是不是給我打了“只報(bào)喜不報(bào)憂”的標(biāo)簽?

          星球里也有不少球友給我發(fā)來(lái)喜訊,難道說(shuō)每年都在涼涼的 Java 后端又承擔(dān)起了就業(yè)的重任?!

          不可能,絕對(duì)不可能,這一切都是假象!反正我敢肯定,還有不少同學(xué)在嗷嗷叫,尤其是 24 屆春招還沒(méi)上岸的,25 屆沒(méi)找到暑期實(shí)習(xí)的(??)。

          我只能說(shuō)拿到 offer 的,這個(gè)假期就放肆幾天吧;沒(méi)拿到的要不就茍一茍,繼續(xù)背背八股,優(yōu)化優(yōu)化簡(jiǎn)歷?也許好運(yùn)就要降臨到你頭上了。

          這次我們就以《Java 面試指南——攜程面經(jīng)》為例,繼續(xù)來(lái)看看攜程這家不錯(cuò)的互聯(lián)網(wǎng)中廠面試官都喜歡問(wèn)哪些問(wèn)題,好做到知彼知己百戰(zhàn)不殆,我會(huì)用通俗易懂+手繪圖的方式,讓天下所有的面渣都能逆襲 ??

          二哥的 Java 面試指南

          內(nèi)容較長(zhǎng),建議正在沖刺 24 屆春招和 25 屆暑期實(shí)習(xí)、秋招的同學(xué)先收藏起來(lái),面試的時(shí)候大概率會(huì)碰到,

          攜程面經(jīng)(詳細(xì))

          對(duì)象創(chuàng)建到銷毀,內(nèi)存如何分配的,(類加載和對(duì)象創(chuàng)建過(guò)程,CMS,G1內(nèi)存清理和分配)

          當(dāng)我們使用 new 關(guān)鍵字創(chuàng)建一個(gè)對(duì)象的時(shí)候,JVM 首先會(huì)檢查 new 指令的參數(shù)是否能在常量池中定位到一個(gè)類的符號(hào)引用,然后檢查這個(gè)符號(hào)引用代表的類是否已被加載、解析和初始化過(guò)。如果沒(méi)有,就先執(zhí)行相應(yīng)的類加載過(guò)程。

          如果已經(jīng)加載,JVM 會(huì)為新生對(duì)象分配內(nèi)存,內(nèi)存分配完成之后,JVM 將分配到的內(nèi)存空間初始化為零值(成員變量,數(shù)值類型是 0,布爾類型是 false,對(duì)象類型是 null),接下來(lái)設(shè)置對(duì)象頭,對(duì)象頭里包含了對(duì)象是哪個(gè)類的實(shí)例、對(duì)象的哈希碼、對(duì)象的 GC 分代年齡等信息。

          最后,JVM 會(huì)執(zhí)行構(gòu)造方法(<init>),將成員變量賦值為預(yù)期的值,這樣一個(gè)對(duì)象就創(chuàng)建完成了。

          二哥的 Java 進(jìn)階之路:對(duì)象的創(chuàng)建過(guò)程

          對(duì)象的銷毀過(guò)程了解嗎?

          對(duì)象創(chuàng)建完成后,就可以通過(guò)引用來(lái)訪問(wèn)對(duì)象的方法和屬性,當(dāng)對(duì)象不再被任何引用指向時(shí),對(duì)象就會(huì)變成垃圾。

          垃圾收集器會(huì)通過(guò)可達(dá)性分析算法判斷對(duì)象是否存活,如果對(duì)象不可達(dá),就會(huì)被回收。

          垃圾收集器會(huì)通過(guò)標(biāo)記清除、標(biāo)記復(fù)制、標(biāo)記整理等算法來(lái)回收內(nèi)存,將對(duì)象占用的內(nèi)存空間釋放出來(lái)。

          常用的垃圾收集器有 CMS、G1、ZGC 等,它們的回收策略和效率不同,可以根據(jù)具體的場(chǎng)景選擇合適的垃圾收集器。

          內(nèi)存如何分配的?

          在堆內(nèi)存分配對(duì)象時(shí),主要使用兩種策略:指針碰撞和空閑列表。

          三分惡面渣逆襲:指針碰撞和空閑列表

          ①、指針碰撞(Bump the Pointer)

          假設(shè)堆內(nèi)存是一個(gè)連續(xù)的空間,分為兩個(gè)部分,一部分是已經(jīng)被使用的內(nèi)存,另一部分是未被使用的內(nèi)存。

          在分配內(nèi)存時(shí),Java 虛擬機(jī)維護(hù)一個(gè)指針,指向下一個(gè)可用的內(nèi)存地址,每次分配內(nèi)存時(shí),只需要將指針向后移動(dòng)(碰撞)一段距離,然后將這段內(nèi)存分配給對(duì)象實(shí)例即可。

          ②、空閑列表(Free List)

          JVM 維護(hù)一個(gè)列表,記錄堆中所有未占用的內(nèi)存塊,每個(gè)空間塊都記錄了大小和地址信息。

          當(dāng)有新的對(duì)象請(qǐng)求內(nèi)存時(shí),JVM 會(huì)遍歷空閑列表,尋找足夠大的空間來(lái)存放新對(duì)象。

          分配后,如果選中的空閑塊未被完全利用,剩余的部分會(huì)作為一個(gè)新的空閑塊加入到空閑列表中。

          指針碰撞適用于管理簡(jiǎn)單、碎片化較少的內(nèi)存區(qū)域(如年輕代),而空閑列表適用于內(nèi)存碎片化較嚴(yán)重或?qū)ο蟠笮〔町愝^大的場(chǎng)景(如老年代)。

          能詳細(xì)說(shuō)一下 CMS 收集器的垃圾收集過(guò)程嗎?

          三分惡面渣逆襲:Concurrent Mark Sweep收集器運(yùn)行示意圖

          CMS(Concurrent Mark Sweep)分 4 大步進(jìn)行垃圾收集:

          • 初始標(biāo)記(Initial Mark):標(biāo)記所有從 GC Roots 直接可達(dá)的對(duì)象,這個(gè)階段需要 STW,但速度很快。
          • 并發(fā)標(biāo)記(Concurrent Mark):從初始標(biāo)記的對(duì)象出發(fā),遍歷所有對(duì)象,標(biāo)記所有可達(dá)的對(duì)象。這個(gè)階段是并發(fā)進(jìn)行的,STW。
          • 重新標(biāo)記(Remark):完成剩余的標(biāo)記工作,包括處理并發(fā)階段遺留下來(lái)的少量變動(dòng),這個(gè)階段通常需要短暫的 STW 停頓。
          • 并發(fā)清除(Concurrent Sweep):清除未被標(biāo)記的對(duì)象,回收它們占用的內(nèi)存空間。

          G1 垃圾收集器了解嗎?

          G1 收集器的運(yùn)行過(guò)程大致可劃分為這幾個(gè)步驟:

          ①、并發(fā)標(biāo)記,G1 通過(guò)并發(fā)標(biāo)記的方式找出堆中的垃圾對(duì)象。并發(fā)標(biāo)記階段與應(yīng)用線程同時(shí)執(zhí)行,不會(huì)導(dǎo)致應(yīng)用線程暫停。

          ②、混合收集,在并發(fā)標(biāo)記完成后,G1 會(huì)計(jì)算出哪些區(qū)域的回收價(jià)值最高(也就是包含最多垃圾的區(qū)域),然后優(yōu)先回收這些區(qū)域。這種回收方式包括了部分新生代區(qū)域和老年代區(qū)域。

          選擇回收成本低而收益高的區(qū)域進(jìn)行回收,可以提高回收效率和減少停頓時(shí)間。

          ③、可預(yù)測(cè)的停頓,G1 在垃圾回收期間仍然需要「Stop the World」。不過(guò),G1 在停頓時(shí)間上添加了預(yù)測(cè)機(jī)制,用戶可以 JVM 啟動(dòng)時(shí)指定期望停頓時(shí)間,G1 會(huì)盡可能地在這個(gè)時(shí)間內(nèi)完成垃圾回收。

          三分惡面渣逆襲:G1收集器運(yùn)行示意圖

          ThreadLocal,(作用,演進(jìn),軟指針,刪除過(guò)程)

          ThreadLocal 是 Java 中提供的一種用于實(shí)現(xiàn)線程局部變量的工具類。它允許每個(gè)線程都擁有自己的獨(dú)立副本,從而實(shí)現(xiàn)線程隔離,用于解決多線程中共享對(duì)象的線程安全問(wèn)題。

          三分惡面渣逆襲:ThreadLocal線程副本

          ThreadLocal 本身并不存儲(chǔ)任何值,它只是作為一個(gè)映射,來(lái)映射線程的局部變量。當(dāng)一個(gè)線程調(diào)用 ThreadLocal 的 set 或 get 方法時(shí),實(shí)際上是訪問(wèn)線程自己的 ThreadLocal.ThreadLocalMap。

          二哥的 Java 進(jìn)階之路

          ThreadLocalMap 是 ThreadLocal 的靜態(tài)內(nèi)部類,它內(nèi)部維護(hù)了一個(gè) Entry 數(shù)組,key 是 ThreadLocal 對(duì)象,value 是線程的局部變量本身。

          三分惡面渣逆襲:ThreadLoca結(jié)構(gòu)圖

          早期的 ThreadLocal 不是這樣的,它的 ThreadLocalMap 中使用 Thread 作為 key,這也是最簡(jiǎn)單的實(shí)現(xiàn)方式。

          黑馬:JDK 早期設(shè)計(jì)

          優(yōu)化后的方案有兩個(gè)好處,一個(gè)是 Map 中存儲(chǔ)的鍵值對(duì)變少了;另一個(gè)是 ThreadLocalMap 的生命周期和線程一樣長(zhǎng),線程銷毀的時(shí)候,ThreadLocalMap 也會(huì)被銷毀。

          Entry 繼承了 WeakReference,它限定了 key 是一個(gè)弱引用,弱引用的好處是當(dāng)內(nèi)存不足時(shí),JVM 會(huì)回收 ThreadLocal 對(duì)象,并且將其對(duì)應(yīng)的 Entry 的 value 設(shè)置為 null,這樣在很大程度上可以避免內(nèi)存泄漏。

          使用完 ThreadLocal 后,及時(shí)調(diào)用 remove() 方法釋放內(nèi)存空間。

          try {
              threadLocal.set(value);
              // 執(zhí)行業(yè)務(wù)操作
          finally {
              threadLocal.remove(); // 確保能夠執(zhí)行清理
          }

          remove() 方法會(huì)將當(dāng)前線程的 ThreadLocalMap 中的所有 key 為 null 的 Entry 全部清除。

          private void remove(ThreadLocal<?> key) {
              Entry[] tab = table;
              int len = tab.length;
              int i = key.threadLocalHashCode & (len-1);
              for (Entry e = tab[i];
                      e != null;
                      e = tab[i = nextIndex(i, len)]) {
                  if (e.get() == key) {
                      e.clear();
                      expungeStaleEntry(i);
                      return;
                  }
              }
          }

          public void clear() {
              this.referent = null;
          }

          線程上下文切換(我答的內(nèi)核態(tài)和用戶態(tài)切換時(shí)機(jī),和切換需要加載哪些內(nèi)容)

          使用多線程的目的是為了充分利用 CPU,但是我們知道,并發(fā)其實(shí)是一個(gè) CPU 來(lái)應(yīng)付多個(gè)線程。

          三分惡面渣逆襲:線程切換

          為了讓用戶感覺(jué)多個(gè)線程是在同時(shí)執(zhí)行的, CPU 資源的分配采用了時(shí)間片輪轉(zhuǎn)也就是給每個(gè)線程分配一個(gè)時(shí)間片,線程在時(shí)間片內(nèi)占用 CPU 執(zhí)行任務(wù)。當(dāng)線程使用完時(shí)間片后,就會(huì)處于就緒狀態(tài)并讓出 CPU 讓其他線程占用,這就是上下文切換。

          三分惡面渣逆襲:上下文切換時(shí)機(jī)

          cas和aba(原子操作+時(shí)間戳)

          CAS(Compare-and-Swap)是一種樂(lè)觀鎖的實(shí)現(xiàn)方式,全稱為“比較并交換”,是一種無(wú)鎖的原子操作。

          在 Java 中,我們可以使用 synchronized關(guān)鍵字和 CAS 來(lái)實(shí)現(xiàn)加鎖效果。

          synchronized 是悲觀鎖,盡管隨著 JDK 版本的升級(jí),synchronized 關(guān)鍵字已經(jīng)“輕量級(jí)”了很多,但依然是悲觀鎖,線程開(kāi)始執(zhí)行第一步就要獲取鎖,一旦獲得鎖,其他的線程進(jìn)入后就會(huì)阻塞并等待鎖。

          CAS 是樂(lè)觀鎖,線程執(zhí)行的時(shí)候不會(huì)加鎖,它會(huì)假設(shè)此時(shí)沒(méi)有沖突,然后完成某項(xiàng)操作;如果因?yàn)闆_突失敗了就重試,直到成功為止。

          在 CAS 中,有這樣三個(gè)值:

          • V:要更新的變量(var)
          • E:預(yù)期值(expected)
          • N:新值(new)

          比較并交換的過(guò)程如下:

          判斷 V 是否等于 E,如果等于,將 V 的值設(shè)置為 N;如果不等,說(shuō)明已經(jīng)有其它線程更新了 V,于是當(dāng)前線程放棄更新,什么都不做。

          這里的預(yù)期值 E 本質(zhì)上指的是“舊值”。

          這個(gè)比較和替換的操作是原子的,即不可中斷,確保了數(shù)據(jù)的一致性。

          什么是 ABA 問(wèn)題?如何解決?

          如果一個(gè)位置的值原來(lái)是 A,后來(lái)被改為 B,再后來(lái)又被改回 A,那么進(jìn)行 CAS 操作的線程將無(wú)法知曉該位置的值在此期間已經(jīng)被修改過(guò)。

          可以使用版本號(hào)/時(shí)間戳的方式來(lái)解決 ABA 問(wèn)題。

          比如說(shuō),每次變量更新時(shí),不僅更新變量的值,還更新一個(gè)版本號(hào)。CAS 操作時(shí)不僅要求值匹配,還要求版本號(hào)匹配。

          Java 的 AtomicStampedReference 類就實(shí)現(xiàn)了這種機(jī)制,它會(huì)同時(shí)檢查引用值和 stamp 是否都相等。

          二哥的 Java 進(jìn)階之路:AtomicStampedReference

          volatile如何保證可見(jiàn)性(cup緩存和主緩存)

          當(dāng)一個(gè)變量被聲明為 volatile 時(shí),Java 內(nèi)存模型會(huì)確保所有線程看到該變量時(shí)的值是一致的。

          深入淺出 Java 多線程:Java內(nèi)存模型

          也就是說(shuō),當(dāng)線程對(duì) volatile 變量進(jìn)行寫(xiě)操作時(shí),JMM 會(huì)在寫(xiě)入這個(gè)變量之后插入一個(gè) Store-Barrier(寫(xiě)屏障)指令,這個(gè)指令會(huì)強(qiáng)制將本地內(nèi)存中的變量值刷新到主內(nèi)存中。

          三分惡面渣逆襲:volatile寫(xiě)插入內(nèi)存屏障后生成的指令序列示意圖

          當(dāng)線程對(duì) volatile 變量進(jìn)行讀操作時(shí),JMM 會(huì)插入一個(gè) Load-Barrier(讀屏障)指令,這個(gè)指令會(huì)強(qiáng)制讓本地內(nèi)存中的變量值失效,從而重新從主內(nèi)存中讀取最新的值。

          三分惡面渣逆襲:volatile寫(xiě)插入內(nèi)存屏障后生成的指令序列示意圖

          例如,我們聲明一個(gè) volatile 變量 x:

          volatile int x = 0

          線程 A 對(duì) x 寫(xiě)入后會(huì)將其最新的值刷新到主內(nèi)存中,線程 B 讀取 x 時(shí)由于本地內(nèi)存中的 x 失效了,就會(huì)從主內(nèi)存中讀取最新的值,內(nèi)存可見(jiàn)性達(dá)成!

          三分惡面渣逆襲:volatile內(nèi)存可見(jiàn)性

          HashMap為什么用紅黑樹(shù),鏈表轉(zhuǎn)數(shù)條件,紅黑樹(shù)插入刪除規(guī)則

          三分惡面渣逆襲:JDK 8 HashMap 數(shù)據(jù)結(jié)構(gòu)示意圖

          HashMap 的核心是一個(gè)動(dòng)態(tài)數(shù)組(Node[] table),用于存儲(chǔ)鍵值對(duì)。這個(gè)數(shù)組的每個(gè)元素稱為一個(gè)“桶”(Bucket),每個(gè)桶的索引是通過(guò)對(duì)鍵的哈希值進(jìn)行哈希函數(shù)處理得到的。

          當(dāng)多個(gè)鍵經(jīng)哈希處理后得到相同的索引時(shí),會(huì)發(fā)生哈希沖突。HashMap 通過(guò)鏈表來(lái)解決哈希沖突——即將具有相同索引的鍵值對(duì)通過(guò)鏈表連接起來(lái)。

          不過(guò),鏈表過(guò)長(zhǎng)時(shí),查詢效率會(huì)比較低,于是當(dāng)鏈表的長(zhǎng)度超過(guò) 8 時(shí)(且數(shù)組的長(zhǎng)度大于 64),鏈表就會(huì)轉(zhuǎn)換為紅黑樹(shù)。紅黑樹(shù)的查詢效率是 O(logn),比鏈表的 O(n) 要快。數(shù)組的查詢效率是 O(1)。

          紅黑樹(shù)怎么保持平衡的?

          紅黑樹(shù)有兩種方式保持平衡:旋轉(zhuǎn)染色

          ①、旋轉(zhuǎn):旋轉(zhuǎn)分為兩種,左旋和右旋

          三分惡面渣逆襲:左旋
          三分惡面渣逆襲:右旋

          ②、染?:

          三分惡面渣逆襲:染色

          參考鏈接

          • 三分惡的面渣逆襲:https://javabetter.cn/sidebar/sanfene/nixi.html
          • 二哥的 Java 進(jìn)階之路:https://javabetter.cn

          ending

          一個(gè)人可以走得很快,但一群人才能走得更遠(yuǎn)。二哥的編程星球已經(jīng)有 5100 多名球友加入了,如果你也需要一個(gè)良好的學(xué)習(xí)環(huán)境,戳鏈接 ?? 加入我們吧。這是一個(gè)編程學(xué)習(xí)指南 + Java 項(xiàng)目實(shí)戰(zhàn) + LeetCode 刷題的私密圈子,你可以閱讀星球?qū)凇⑾蚨缣釂?wèn)、幫你制定學(xué)習(xí)計(jì)劃、和球友一起打卡成長(zhǎng)。

          兩個(gè)置頂帖「球友必看」和「知識(shí)圖譜」里已經(jīng)沉淀了非常多優(yōu)質(zhì)的學(xué)習(xí)資源,相信能幫助你走的更快、更穩(wěn)、更遠(yuǎn)

          歡迎點(diǎn)擊左下角閱讀原文了解二哥的編程星球,這可能是你學(xué)習(xí)求職路上最有含金量的一次點(diǎn)擊。

          最后,把二哥的座右銘送給大家:沒(méi)有什么使我停留——除了目的,縱然岸旁有玫瑰、有綠蔭、有寧?kù)o的港灣,我是不系之舟。共勉 ??。

          瀏覽 2661
          3點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          3點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日韩免费爱爱视频网站 | 欧美性爱一级棒 | 久久久春色 | 69精品又硬又爽又粗少妇 | 超碰超碰成人 |