成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

中廠Java后端15連問!

開發(fā) 后端
G1(Garbage-First)收集器是 Java 虛擬機(jī)中的一種垃圾收集器。它于 JDK 7 中首次引入,并在后續(xù)版本中不斷改進(jìn)優(yōu)化。

前言

大家好,我是田螺。最近一位星球粉絲去面試一個(gè)中廠,Java后端。他說,好幾道題答不上來(lái),于是我?guī)兔φ砹艘徊ù鸢?/p>

  1. G1收集器
  2. JVM內(nèi)存劃分
  3. 對(duì)象進(jìn)入老年代標(biāo)志
  4. 你在項(xiàng)目中用到的是哪種收集器,怎么調(diào)優(yōu)的
  5. new對(duì)象的內(nèi)存分布
  6. 局部變量的內(nèi)存分布
  7. Synchronized和Lock的區(qū)別
  8. Synchronized原理
  9. 可重入是如何知道當(dāng)前鎖的擁有著的
  10. Spring用到的設(shè)計(jì)模式
  11. 說說SPI
  12. 排行榜怎么設(shè)計(jì)
  13. SpringBoot 中注解實(shí)現(xiàn)緩存用過沒?實(shí)現(xiàn)原理是什么。
  14. 深分頁(yè)優(yōu)化
  15. Redis分布式鎖如何進(jìn)一步提升性能

1. 說說G1收集器

G1(Garbage-First)收集器是 Java 虛擬機(jī)中的一種垃圾收集器。它于 JDK 7 中首次引入,并在后續(xù)版本中不斷改進(jìn)優(yōu)化。

  • 可以使用 -XX:+UseG1GC 開啟它。這個(gè)選項(xiàng)告訴 JVM 在運(yùn)行時(shí)使用 G1 垃圾收集器來(lái)管理堆內(nèi)存。
  • G1(Garbage-First)收集器的核心原則之一就是“首先收集盡可能多的垃圾”,即優(yōu)先回收那些包含最多垃圾的區(qū)域。這個(gè)原則是與CMS收集器有所不同的,CMS主要關(guān)注于盡可能減少應(yīng)用程序的停頓時(shí)間。
  • G1 收集器會(huì)將 Java 堆劃分為多個(gè)大小相等的區(qū)域(Region),然后根據(jù)當(dāng)前堆內(nèi)存的使用情況,選擇性地進(jìn)行垃圾回收。
  • 當(dāng) G1 收集器決定進(jìn)行Full GC時(shí),它會(huì)執(zhí)行一次 Full GC(Full GC),這時(shí)整個(gè)應(yīng)用程序?qū)?huì)暫停(STW)。但在Mixed GC中,G1 收集器會(huì)在某些情況下選擇部分年輕代分區(qū)和部分老年代分區(qū)進(jìn)行回收,這樣一來(lái),即使不是整個(gè)堆內(nèi)存的垃圾回收,仍然可能會(huì)導(dǎo)致一些暫停,但相對(duì)于 Full GC,這種暫停時(shí)間會(huì)更短。
  • 適用于大內(nèi)存、對(duì)停頓時(shí)間敏感、需要高吞吐量的應(yīng)用場(chǎng)景。

2. JVM內(nèi)存劃分

Java 虛擬機(jī)(JVM)的內(nèi)存分為多個(gè)區(qū)域,每個(gè)區(qū)域都有不同的作用和管理方式。JVM 內(nèi)存劃分的主要區(qū)域:

圖片圖片

  • 堆(Heap):堆是 JVM 中最大的一塊內(nèi)存區(qū)域,用于存儲(chǔ)對(duì)象實(shí)例和數(shù)組。堆內(nèi)存由所有線程共享,是垃圾收集器主要管理的區(qū)域。
  • 程序計(jì)數(shù)器(Program Counter):程序計(jì)數(shù)器是一塊較小的內(nèi)存空間,它是線程私有的,用于存儲(chǔ)當(dāng)前線程正在執(zhí)行的字節(jié)碼指令的地址。在多線程環(huán)境下,每個(gè)線程都有一個(gè)獨(dú)立的程序計(jì)數(shù)器,以保證線程切換后能夠恢復(fù)到正確的執(zhí)行位置。
  • 虛擬機(jī)棧(Java Virtual Machine Stacks):虛擬機(jī)棧也是線程私有的,用于存儲(chǔ)方法執(zhí)行過程中的局部變量、方法參數(shù)、中間結(jié)果等數(shù)據(jù)。每個(gè)方法在執(zhí)行時(shí)都會(huì)創(chuàng)建一個(gè)棧幀,棧幀包含了方法的局部變量表、操作數(shù)棧、動(dòng)態(tài)鏈接、方法返回地址等信息。
  • 本地方法棧(Native Method Stacks):本地方法棧與虛擬機(jī)棧類似,用于執(zhí)行本地方法(Native Method)時(shí)的數(shù)據(jù)存儲(chǔ)。與虛擬機(jī)棧一樣,本地方法棧也是線程私有的。
  • 方法區(qū)(Method Area):方法區(qū)用于存儲(chǔ)類信息、常量、靜態(tài)變量和即時(shí)編譯器編譯后的代碼等數(shù)據(jù)。在jdk7及以前,習(xí)慣上把方法區(qū),稱為永久代。jdk8開始,使用元空間取代了永久代。本質(zhì)上,方法區(qū)和永久代并不等價(jià)。通過-XX:Permsize來(lái)設(shè)置永久代初始分配空間??梢允褂脜?shù) -XX:MetaspaceSize 和 -XX:MaxMetaspaceSize指定默認(rèn)值依賴于平臺(tái)。
  • 運(yùn)行時(shí)常量池(Runtime Constant Pool):運(yùn)行時(shí)常量池是方法區(qū)的一部分,用于存儲(chǔ)編譯時(shí)生成的字面量常量和符號(hào)引用。與類文件中的常量池(Constant Pool)相對(duì)應(yīng),運(yùn)行時(shí)常量池具有動(dòng)態(tài)性,可以在運(yùn)行時(shí)動(dòng)態(tài)地添加、修改常量。
  • 直接內(nèi)存(Direct Memory):直接內(nèi)存不是 JVM 內(nèi)存的一部分,但是在一些情況下會(huì)被 JVM 使用。直接內(nèi)存是通過使用 java.nio 包中的類來(lái)申請(qǐng)和釋放的,它允許 JVM 在堆外分配內(nèi)存,可以提高 I/O 操作的效率。

3. 對(duì)象進(jìn)入老年代標(biāo)志

圖片圖片

  • 對(duì)象年齡達(dá)到閾值:對(duì)象在 Java 堆中的存活時(shí)間通常會(huì)通過對(duì)象年齡(Age)來(lái)衡量。在某些垃圾收集器中,當(dāng)對(duì)象經(jīng)過多次垃圾收集后仍然存活,并且達(dá)到了一定的年齡閾值,就會(huì)被晉升到老年代。年齡閾值可以通過 JVM 參數(shù)進(jìn)行調(diào)整。
  • 大對(duì)象:大對(duì)象通常指的是占用大量?jī)?nèi)存空間的對(duì)象,例如數(shù)組或者很大的字符串。在一些垃圾收集器中,為了避免在新生代中頻繁復(fù)制大對(duì)象,會(huì)直接將大對(duì)象分配在老年代中。
  • 長(zhǎng)期存活的對(duì)象:一些長(zhǎng)期存活的對(duì)象,例如長(zhǎng)期存在的線程、靜態(tài)變量等,有可能直接被分配到老年代中。
  • 晉升失敗:當(dāng)新生代中的對(duì)象經(jīng)過多次垃圾回收仍然存活,并且新生代內(nèi)存不足以容納這些存活對(duì)象時(shí),會(huì)發(fā)生一次晉升失敗,這時(shí)一部分存活對(duì)象可能會(huì)被直接晉升到老年代。

通常情況下,老年代用于存放長(zhǎng)期存活的對(duì)象,以減少垃圾收集的頻率和提高垃圾回收的效率。

4. 你在項(xiàng)目中用到的是哪種收集器,怎么調(diào)優(yōu)的

我列舉了常見的垃圾收集器以及調(diào)優(yōu)策略:

串行收集器(Serial Garbage Collector):

  • 適用于單核 CPU 或小型應(yīng)用場(chǎng)景。
  • 調(diào)優(yōu)參數(shù):-XX:+UseSerialGC

并行收集器(Parallel Garbage Collector):

  • 適用于多核 CPU,通過并行收集來(lái)提高垃圾回收效率。
  • 調(diào)優(yōu)參數(shù):-XX:+UseParallelGC

并發(fā)標(biāo)記-清除收集器(Concurrent Mark-Sweep Garbage Collector,CMS GC):

  • 適用于對(duì)系統(tǒng)停頓時(shí)間敏感的應(yīng)用場(chǎng)景。
  • 調(diào)優(yōu)參數(shù):-XX:+UseConcMarkSweepGC

G1 收集器(Garbage-First Garbage Collector):

  • 適用于大內(nèi)存、對(duì)停頓時(shí)間敏感、需要高吞吐量的應(yīng)用場(chǎng)景。
  • 調(diào)優(yōu)參數(shù):-XX:+UseG1GC

ZGC 和 Shenandoah(JDK 11+):

  • 適用于超大內(nèi)存、對(duì)停頓時(shí)間極為敏感的應(yīng)用場(chǎng)景。
  • 調(diào)優(yōu)參數(shù):-XX:+UseZGC(ZGC)、-XX:+UseShenandoahGC(Shenandoah)

當(dāng)然,調(diào)優(yōu)的具體策略會(huì)根據(jù)應(yīng)用的特點(diǎn)和需求來(lái)定,可以通過以下一些常見的調(diào)優(yōu)手段來(lái)改進(jìn)垃圾收集器的性能:

  • 調(diào)整堆大?。?Xms、-Xmx)以及新生代與老年代的比例(-XX:NewRatio、-XX:SurvivorRatio)。
  • 設(shè)置垃圾收集器的參數(shù),如并行收集器的線程數(shù)(-XX:ParallelGCThreads)、并發(fā)標(biāo)記-清除收集器的初始標(biāo)記階段并發(fā)線程數(shù)(-XX:ConcGCThreads)等。
  • 設(shè)置垃圾收集器的觸發(fā)條件,如新生代垃圾收集的觸發(fā)條件(-XX:MaxNewSize、-XX:NewThreshold)等。
  • 監(jiān)控和分析 GC 日志,根據(jù)應(yīng)用的實(shí)際情況進(jìn)行優(yōu)化。選擇合適的 GC 日志分析工具,如GCViewer、GCEasy等,進(jìn)行進(jìn)一步的性能分析和優(yōu)化。

5. new對(duì)象的內(nèi)存分布

在 Java 中,當(dāng)使用 new 關(guān)鍵字創(chuàng)建一個(gè)對(duì)象時(shí),對(duì)象在內(nèi)存中的基本結(jié)構(gòu)通常由對(duì)象頭、實(shí)例數(shù)據(jù)和填充組成。

  • 對(duì)象頭(Object Header):對(duì)象頭存儲(chǔ)了對(duì)象的元數(shù)據(jù)信息,如哈希碼、對(duì)象鎖狀態(tài)、GC 相關(guān)信息等。對(duì)象頭的結(jié)構(gòu)和大小在不同的 JVM 實(shí)現(xiàn)中可能會(huì)有所不同,但通常包括一些固定的字段。
  • 實(shí)例數(shù)據(jù)(Instance Data):實(shí)例數(shù)據(jù)包含了對(duì)象的實(shí)際數(shù)據(jù),即對(duì)象中的成員變量的值。這些數(shù)據(jù)根據(jù)對(duì)象的類定義來(lái)確定,包括各種類型的字段和對(duì)象引用等。
  • 填充(Padding):填充是為了滿足內(nèi)存對(duì)齊的需要而添加的額外字節(jié)。內(nèi)存對(duì)齊可以提高內(nèi)存訪問的效率,一些 JVM 可能會(huì)在對(duì)象的實(shí)例數(shù)據(jù)后添加填充字節(jié),使得對(duì)象的起始地址能夠?qū)R到某個(gè)特定的邊界。

6. 局部變量的內(nèi)存分布

棧幀結(jié)構(gòu):

  • 棧幀由三部分組成:局部變量表(Local Variable Table)、操作數(shù)棧(Operand Stack)和幀數(shù)據(jù)(Frame Data)。
  • 局部變量表用于存儲(chǔ)方法參數(shù)和方法內(nèi)部定義的局部變量。
  • 操作數(shù)棧用于存儲(chǔ)方法執(zhí)行過程中的操作數(shù)。
  • 幀數(shù)據(jù)包含了方法的異常處理信息、方法返回地址等。

局部變量表:

  • 局部變量表是一個(gè)數(shù)組,用于存儲(chǔ)方法參數(shù)和方法內(nèi)部定義的局部變量。
  • 局部變量表中的每個(gè)元素都可以存儲(chǔ)一個(gè)數(shù)據(jù)值,數(shù)據(jù)類型可以是基本數(shù)據(jù)類型或者引用類型。
  • 局部變量表中的變量只在方法執(zhí)行期間有效,當(dāng)方法執(zhí)行結(jié)束后,局部變量表所占用的內(nèi)存空間會(huì)被釋放。

局部變量的存儲(chǔ)位置:

  • 對(duì)于基本數(shù)據(jù)類型的局部變量,它們的值直接存儲(chǔ)在局部變量表中。
  • 對(duì)于引用類型的局部變量,局部變量表中存儲(chǔ)的是對(duì)象的引用,而對(duì)象的實(shí)際數(shù)據(jù)存儲(chǔ)在堆內(nèi)存中。

局部變量的生命周期:

  • 局部變量的生命周期與方法的執(zhí)行周期相同,當(dāng)方法執(zhí)行結(jié)束后,局部變量表所占用的內(nèi)存空間會(huì)被釋放。
  • 局部變量的生命周期也可能會(huì)被延長(zhǎng),比如局部變量被捕獲到一個(gè)匿名內(nèi)部類中,那么該局部變量的生命周期會(huì)與匿名內(nèi)部類的生命周期保持一致。

7.Synchronized和ReenTrantLock的區(qū)別

  • Synchronized是依賴于JVM實(shí)現(xiàn)的,而ReenTrantLock是API實(shí)現(xiàn)的。
  • 在Synchronized優(yōu)化以前,synchronized的性能是比ReenTrantLock差很多的,但是自從Synchronized引入了偏向鎖,輕量級(jí)鎖(自旋鎖)后,兩者性能就差不多了。
  • Synchronized的使用比較方便簡(jiǎn)潔,它由編譯器去保證鎖的加鎖和釋放。而ReenTrantLock需要手工聲明來(lái)加鎖和釋放鎖,最好在finally中聲明釋放鎖。
  • ReentrantLock可以指定是公平鎖還是?公平鎖。?synchronized只能是?公平鎖。
  • ReentrantLock可響應(yīng)中斷、可輪回,而Synchronized是不可以響應(yīng)中斷的

8.Synchronized原理

synchronized是Java中的關(guān)鍵字,是一種同步鎖。synchronized關(guān)鍵字可以作用于方法或者代碼塊。

一般面試時(shí)??梢赃@么回答:

  • 反編譯后,monitorenter、monitorexit、ACC_SYNCHRONIZED
  • monitor監(jiān)視器
  • Java Monitor 的工作機(jī)理
  • 對(duì)象與monitor關(guān)聯(lián)

8.1 monitorenter、monitorexit、ACC_SYNCHRONIZED

  • 如果synchronized作用于代碼塊,反編譯可以看到兩個(gè)指令:monitorenter、monitorexit,JVM使用monitorenter和monitorexit兩個(gè)指令實(shí)現(xiàn)同步;
  • 如果作用synchronized作用于方法,反編譯可以看到ACCSYNCHRONIZED標(biāo)記,JVM通過在方法訪問標(biāo)識(shí)符(flags)中加入ACCSYNCHRONIZED來(lái)實(shí)現(xiàn)同步功能。
  • 同步代碼塊是通過monitorenter和monitorexit來(lái)實(shí)現(xiàn),當(dāng)線程執(zhí)行到monitorenter的時(shí)候要先獲得monitor鎖,才能執(zhí)行后面的方法。當(dāng)線程執(zhí)行到monitorexit的時(shí)候則要釋放鎖。
  • 同步方法是通過中設(shè)置ACCSYNCHRONIZED標(biāo)志來(lái)實(shí)現(xiàn),當(dāng)線程執(zhí)行有ACCSYNCHRONIZED標(biāo)志的方法,需要獲得monitor鎖。每個(gè)對(duì)象都與一個(gè)monitor相關(guān)聯(lián),線程可以占有或者釋放monitor。

8.2 monitor監(jiān)視器

monitor是什么呢?操作系統(tǒng)的管程(monitors)是概念原理,ObjectMonitor是它的原理實(shí)現(xiàn)。

在Java虛擬機(jī)(HotSpot)中,Monitor(管程)是由ObjectMonitor實(shí)現(xiàn)的,其主要數(shù)據(jù)結(jié)構(gòu)如下:

ObjectMonitor() {
    _header       = NULL;
    _count        = 0; // 記錄個(gè)數(shù)
    _waiters      = 0,
    _recursions   = 0;
    _object       = NULL;
    _owner        = NULL;
    _WaitSet      = NULL;  // 處于wait狀態(tài)的線程,會(huì)被加入到_WaitSet
    _WaitSetLock  = 0 ;
    _Responsible  = NULL ;
    _succ         = NULL ;
    _cxq          = NULL ;
    FreeNext      = NULL ;
    _EntryList    = NULL ;  // 處于等待鎖block狀態(tài)的線程,會(huì)被加入到該列表
    _SpinFreq     = 0 ;
    _SpinClock    = 0 ;
    OwnerIsThread = 0 ;
  }

ObjectMonitor中幾個(gè)關(guān)鍵字段的含義如圖所示:

圖片圖片

8.3 Java Monitor 的工作機(jī)理

圖片圖片

  • 想要獲取monitor的線程,首先會(huì)進(jìn)入_EntryList隊(duì)列。
  • 當(dāng)某個(gè)線程獲取到對(duì)象的monitor后,進(jìn)入Owner區(qū)域,設(shè)置為當(dāng)前線程,同時(shí)計(jì)數(shù)器count加1。
  • 如果線程調(diào)用了wait()方法,則會(huì)進(jìn)入WaitSet隊(duì)列。它會(huì)釋放monitor鎖,即將owner賦值為null,count自減1,進(jìn)入WaitSet隊(duì)列阻塞等待。
  • 如果其他線程調(diào)用 notify() / notifyAll() ,會(huì)喚醒WaitSet中的某個(gè)線程,該線程再次嘗試獲取monitor鎖,成功即進(jìn)入Owner區(qū)域。
  • 同步方法執(zhí)行完畢了,線程退出臨界區(qū),會(huì)將monitor的owner設(shè)為null,并釋放監(jiān)視鎖。

8.4 對(duì)象與monitor關(guān)聯(lián)

圖片圖片

  • 在HotSpot虛擬機(jī)中,對(duì)象在內(nèi)存中存儲(chǔ)的布局可以分為3塊區(qū)域:對(duì)象頭(Header),實(shí)例數(shù)據(jù)(Instance Data)和對(duì)象填充(Padding)。
  • 對(duì)象頭主要包括兩部分?jǐn)?shù)據(jù):Mark Word(標(biāo)記字段)、Class Pointer(類型指針)。
  • Mark Word 是用于存儲(chǔ)對(duì)象自身的運(yùn)行時(shí)數(shù)據(jù),如哈希碼(HashCode)、GC分代年齡、鎖狀態(tài)標(biāo)志、線程持有的鎖、偏向線程 ID、偏向時(shí)間戳等。
  • 重量級(jí)鎖,指向互斥量的指針。其實(shí)synchronized是重量級(jí)鎖,也就是說Synchronized的對(duì)象鎖,Mark Word鎖標(biāo)識(shí)位為10,其中指針指向的是Monitor對(duì)象的起始地址。

9.可重入是如何知道當(dāng)前鎖的擁有著的

比如,ReentrantLock 是可重入的鎖。ReentrantLock 類實(shí)現(xiàn)了可重入鎖的概念,允許同一個(gè)線程在持有鎖的情況下多次獲取同一個(gè)鎖,而不會(huì)被阻塞。

在 ReentrantLock 中,每個(gè)鎖都關(guān)聯(lián)著一個(gè)持有計(jì)數(shù)器和一個(gè)擁有者線程。當(dāng)一個(gè)線程首次獲取鎖時(shí),持有計(jì)數(shù)器會(huì)增加;當(dāng)該線程再次獲取鎖時(shí),持有計(jì)數(shù)器會(huì)繼續(xù)增加。每次釋放鎖時(shí),計(jì)數(shù)器會(huì)相應(yīng)減少。只有當(dāng)持有計(jì)數(shù)器減為零時(shí),鎖才會(huì)完全釋放,其他線程才有機(jī)會(huì)獲取鎖。

這樣一來(lái),當(dāng)線程嘗試獲取鎖時(shí),它會(huì)檢查當(dāng)前鎖的持有計(jì)數(shù)器以及擁有者線程。如果鎖未被任何線程持有,或者當(dāng)前線程是鎖的擁有者,那么鎖將立即分配給當(dāng)前線程。否則,當(dāng)前線程會(huì)被阻塞,直到鎖被釋放。

10.Spring用到的設(shè)計(jì)模式

  • 單例模式(Singleton Pattern):Spring 中的 Bean 默認(rèn)是單例的,即每個(gè) Bean 只有一個(gè)實(shí)例。這種方式可以提高性能并減少資源消耗。
  • 工廠模式(Factory Pattern):Spring 使用工廠模式來(lái)創(chuàng)建和管理 Bean。它提供了幾種不同類型的工廠,比如 BeanFactory 和 ApplicationContext,用于創(chuàng)建和管理 Bean 對(duì)象。
  • 代理模式(Proxy Pattern):Spring AOP(面向切面編程)功能基于代理模式實(shí)現(xiàn)。它允許通過在運(yùn)行時(shí)為目標(biāo)對(duì)象創(chuàng)建代理對(duì)象來(lái)添加橫切關(guān)注點(diǎn)(如日志記錄、性能監(jiān)控等)。
  • 裝飾者模式(Decorator Pattern):Spring 中的 BeanPostProcessor 接口就是一個(gè)裝飾器模式的例子。它允許在 Bean 初始化過程中動(dòng)態(tài)地添加新的功能。
  • 觀察者模式(Observer Pattern):Spring 的事件機(jī)制就是基于觀察者模式實(shí)現(xiàn)的。它允許 Bean 發(fā)布事件,其他 Bean 可以注冊(cè)監(jiān)聽器來(lái)響應(yīng)這些事件。
  • 策略模式(Strategy Pattern):Spring 的 IOC(控制反轉(zhuǎn))和 DI(依賴注入)功能基于策略模式實(shí)現(xiàn)。它允許將不同的實(shí)現(xiàn)注入到一個(gè)接口或抽象類中,以便在運(yùn)行時(shí)選擇不同的行為。
  • 模板模式(Template Pattern):Spring 的 JdbcTemplate 和 HibernateTemplate 等模板類就是模板模式的應(yīng)用。它們封裝了一些常見的操作,使開發(fā)者可以通過簡(jiǎn)單的方法調(diào)用來(lái)執(zhí)行數(shù)據(jù)庫(kù)操作。
  • 適配器模式(Adapter Pattern):Spring 的 AOP 功能和 Spring MVC 框架都使用了適配器模式。它們?cè)试S將現(xiàn)有的類與新的接口進(jìn)行適配,以便實(shí)現(xiàn)新的功能。
  • 建造者模式(Builder Pattern):Spring 中的 BeanDefinitionBuilder 和 BeanFactoryBuilder 等構(gòu)建器模式的應(yīng)用。它們用于構(gòu)建復(fù)雜的對(duì)象,并且允許逐步設(shè)置對(duì)象的屬性。

11.聊聊SPI

SPI,其實(shí)就是Service Provider Interface,是Java提供的一種機(jī)制,用于在運(yùn)行時(shí)動(dòng)態(tài)裝載實(shí)現(xiàn)模塊,使得應(yīng)用程序能夠擴(kuò)展、替換特定的服務(wù)或?qū)崿F(xiàn)。

SPI的工作原理主要包括以下幾個(gè)關(guān)鍵點(diǎn):

  • 接口定義:首先,需要定義一個(gè)接口,該接口定義了一組操作或服務(wù)。這個(gè)接口通常由Java核心庫(kù)或者第三方庫(kù)提供。
  • 服務(wù)提供者:其次,可以有多個(gè)服務(wù)提供者來(lái)實(shí)現(xiàn)這個(gè)接口。這些服務(wù)提供者通常是獨(dú)立的模塊或者庫(kù),它們?cè)谧约旱膉ar包中提供了實(shí)現(xiàn)。
  • 配置文件:在Java中,SPI通過在META-INF/services目錄下的特定配置文件中指定實(shí)現(xiàn)類的方式來(lái)實(shí)現(xiàn)動(dòng)態(tài)裝載。具體來(lái)說,SPI機(jī)制要求服務(wù)提供者在這個(gè)目錄下創(chuàng)建一個(gè)以接口全限定名為文件名的文件,文件中列出了具體的實(shí)現(xiàn)類名。
  • 動(dòng)態(tài)加載:當(dāng)應(yīng)用程序需要某個(gè)服務(wù)時(shí),Java運(yùn)行時(shí)會(huì)動(dòng)態(tài)加載配置文件中指定的實(shí)現(xiàn)類,并實(shí)例化它們。這種機(jī)制使得應(yīng)用程序能夠在不修改源代碼的情況下靈活地替換或擴(kuò)展特定的服務(wù)實(shí)現(xiàn)。

在實(shí)際應(yīng)用中,我們可以利用SPI來(lái)實(shí)現(xiàn)插件化架構(gòu)、模塊化開發(fā)等,從而提高代碼的可維護(hù)性和可擴(kuò)展性。

12.排行榜怎么設(shè)計(jì)

可以考慮:數(shù)據(jù)庫(kù)的order by、或者Redis 的zset

大家可以看下我的這篇文章哈:

如何設(shè)計(jì)一個(gè)排行榜

對(duì)于游戲排行榜,如果數(shù)據(jù)量達(dá)到億萬(wàn)級(jí)別,需要考慮的確實(shí)是分桶策略,而桶排序則是分桶策略的一種可能實(shí)現(xiàn)方式之一。

桶排序是一種基于這種分桶策略的排序算法,它將數(shù)據(jù)劃分到若干個(gè)有序的桶中,然后分別對(duì)每個(gè)桶中的數(shù)據(jù)進(jìn)行排序,最后將所有桶中的數(shù)據(jù)按照順序合并起來(lái),得到排好序的結(jié)果。

在游戲排行榜系統(tǒng)中,可以根據(jù)玩家的分?jǐn)?shù)范圍、等級(jí)、地區(qū)等因素來(lái)設(shè)計(jì)分桶策略,將玩家數(shù)據(jù)劃分到不同的桶中。這樣可以使得每個(gè)桶內(nèi)的數(shù)據(jù)量相對(duì)較小,提高了排序的效率。

13.SpringBoot 中注解實(shí)現(xiàn)緩存用過沒?實(shí)現(xiàn)原理是什么。

常見的緩存注解包括 @Cacheable、@CachePut、@CacheEvict 等。這些注解的實(shí)現(xiàn)原理基于Spring提供的緩存抽象。

是的,Spring Boot 中的緩存注解常用于提升系統(tǒng)性能,減少重復(fù)計(jì)算,常見的緩存注解包括 @Cacheable、@CachePut、@CacheEvict 等。這些注解的實(shí)現(xiàn)原理基于 Spring Framework 提供的緩存抽象。

實(shí)現(xiàn)原理:

  1. 代理機(jī)制:
  • Spring Boot 使用 AOP(面向切面編程)的方式,在運(yùn)行時(shí)動(dòng)態(tài)地為帶有緩存注解的方法生成代理對(duì)象。
  • 當(dāng)調(diào)用帶有緩存注解的方法時(shí),實(shí)際上是調(diào)用代理對(duì)象的方法。
  1. 緩存管理器:
  • Spring Boot 提供了多種緩存管理器的實(shí)現(xiàn),比如基于 ConcurrentHashMap 的 SimpleCacheManager、基于 Ehcache的緩存管理器。
  • 緩存管理器負(fù)責(zé)真正地操作緩存,將數(shù)據(jù)存儲(chǔ)到緩存中或者從緩存中獲取數(shù)據(jù)。
  1. 緩存注解:
  • @Cacheable:標(biāo)記在方法上,表示方法的返回值將會(huì)被緩存,當(dāng)方法被調(diào)用時(shí),首先從緩存中查找數(shù)據(jù),如果緩存中存在數(shù)據(jù),則直接返回,否則執(zhí)行方法并將結(jié)果存儲(chǔ)到緩存中。
  • @CachePut:標(biāo)記在方法上,表示方法的返回值將會(huì)被存儲(chǔ)到緩存中,即使緩存中已經(jīng)存在相同 key 的數(shù)據(jù),也會(huì)重新存儲(chǔ)。
  • @CacheEvict:標(biāo)記在方法上,表示清除緩存中的數(shù)據(jù),可以根據(jù)條件來(lái)清除指定的緩存數(shù)據(jù)。
  1. 緩存 key 的生成:
  • 默認(rèn)情況下,緩存 key 是由方法的參數(shù)組成的,默認(rèn)的 key 生成器是 SimpleKeyGenerator。
  • 可以通過自定義 key 生成器來(lái)生成復(fù)雜的緩存 key。
  1. 緩存注解的執(zhí)行流程:
  • 當(dāng)方法被調(diào)用時(shí),首先會(huì)根據(jù)方法參數(shù)生成緩存 key。
  • 然后從緩存中根據(jù)緩存 key 查找數(shù)據(jù),如果找到則返回,否則執(zhí)行方法并將結(jié)果存儲(chǔ)到緩存中。
  • 在 @CachePut 和 @CacheEvict 注解中,會(huì)根據(jù)條件清除緩存中的數(shù)據(jù)或者將數(shù)據(jù)存儲(chǔ)到緩存中。

14.深分頁(yè)優(yōu)化

我們可以通過減少回表次數(shù)來(lái)優(yōu)化。一般有標(biāo)簽記錄法和延遲關(guān)聯(lián)法。

14.1 標(biāo)簽記錄法

就是標(biāo)記一下上次查詢到哪一條了,下次再來(lái)查的時(shí)候,從該條開始往下掃描。就好像看書一樣,上次看到哪里了,你就折疊一下或者夾個(gè)書簽,下次來(lái)看的時(shí)候,直接就翻到啦。

假設(shè)上一次記錄到100000,則SQL可以修改為:

select  id,name,balance FROM account where id > 100000 limit 10;

這樣的話,后面無(wú)論翻多少頁(yè),性能都會(huì)不錯(cuò)的,因?yàn)槊辛薸d索引。但是這種方式有局限性:需要一種類似連續(xù)自增的字段。

14.2 延遲關(guān)聯(lián)法

延遲關(guān)聯(lián)法,就是把條件轉(zhuǎn)移到主鍵索引樹,然后減少回表。假設(shè)原生SQL是這樣的的,其中id是主鍵,create_time是普通索引

select id,name,balance from account where create_time> '2020-09-19' limit 100000,10;

使用延遲關(guān)聯(lián)法優(yōu)化,如下:

select  acct1.id,acct1.name,acct1.balance FROM account acct1 INNER JOIN 
(SELECT a.id FROM account a WHERE a.create_time > '2020-09-19' limit 100000, 10) 
AS acct2 on acct1.id= acct2.id;

優(yōu)化思路就是,先通過idx_create_time二級(jí)索引樹查詢到滿足條件的主鍵ID,再與原表通過主鍵ID內(nèi)連接,這樣后面直接走了主鍵索引了,同時(shí)也減少了回表。

15.分布式鎖如何進(jìn)一步提升性能,答了Redis的實(shí)現(xiàn)思路好像不是面試官想聽的

redis分布式鎖,我覺得可以從一下這幾個(gè)方向來(lái)回答:

  • Pipeline 批量操作:使用 Redis 的 Pipeline 功能可以將多個(gè) Redis 命令打包發(fā)送給服務(wù)器,減少網(wǎng)絡(luò)延遲,提高性能。在獲取鎖、釋放鎖等操作時(shí),可以考慮使用 Pipeline 來(lái)批量執(zhí)行多個(gè)命令。
  • Lua 腳本:Redis 支持 Lua 腳本,可以將多個(gè)操作封裝在一個(gè)腳本中,在服務(wù)器端原子性地執(zhí)行,減少了網(wǎng)絡(luò)通信的開銷??梢詫@取鎖和釋放鎖的邏輯封裝在 Lua 腳本中,以提高性能。
  • 降級(jí)策略:在高并發(fā)情況下,可以考慮引入降級(jí)策略,當(dāng)獲取鎖失敗時(shí),可以使用備用方案或者默認(rèn)值來(lái)處理,而不是一直等待鎖的釋放。
  • 監(jiān)控和優(yōu)化:通過監(jiān)控 Redis 的性能指標(biāo),如連接數(shù)、命令執(zhí)行時(shí)間等,可以及時(shí)發(fā)現(xiàn)性能瓶頸,并進(jìn)行優(yōu)化??梢酝ㄟ^ Redis 的監(jiān)控工具或者第三方監(jiān)控工具來(lái)實(shí)現(xiàn)監(jiān)控。
  • 合理設(shè)置鎖的過期時(shí)間:根據(jù)業(yè)務(wù)場(chǎng)景的特點(diǎn)和需求,合理設(shè)置鎖的過期時(shí)間,避免鎖被長(zhǎng)時(shí)間占用而影響系統(tǒng)性能??梢愿鶕?jù)操作的耗時(shí)和鎖的競(jìng)爭(zhēng)情況來(lái)動(dòng)態(tài)調(diào)整鎖的過期時(shí)間。
  • 使用 Redlock 算法:Redlock 是一種基于多個(gè) Redis 節(jié)點(diǎn)的分布式鎖算法,可以提高分布式鎖的可靠性和性能??梢钥紤]使用 Redlock 算法來(lái)實(shí)現(xiàn)分布式鎖。
責(zé)任編輯:武曉燕 來(lái)源: 撿田螺的小男孩
相關(guān)推薦

2023-01-28 08:24:28

MySQL索引B+樹

2023-04-26 07:40:34

MySQL索引類型存儲(chǔ)

2024-07-04 11:06:47

2022-05-14 21:19:22

ThreadLocaJDKsynchroniz

2022-04-01 12:40:13

MySQL數(shù)據(jù)庫(kù)

2022-12-28 08:33:32

字節(jié)國(guó)際支付

2023-03-10 08:45:15

SQL優(yōu)化統(tǒng)計(jì)

2021-07-12 07:08:52

TCP協(xié)議面試

2021-11-09 09:30:52

OkHttp面試Android

2025-06-03 01:45:00

2020-05-11 15:01:16

JavaJKD 15工具

2020-12-21 07:53:38

財(cái)務(wù)研發(fā)考勤

2020-09-30 18:19:27

RedisJava面試

2023-04-07 08:34:31

2023-02-13 08:18:15

數(shù)據(jù)庫(kù)索引,

2022-02-14 08:25:50

Go語(yǔ)言面試

2024-12-04 08:53:44

Docker腳本命令

2011-06-13 09:29:56

英特爾芯片15nm

2024-05-06 00:00:00

2011-09-30 10:36:07

系統(tǒng)管理測(cè)試
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 91传媒在线观看 | 国产区第一页 | 日韩精品一区二区三区免费观看 | 最新av在线播放 | 天天操天天干天天爽 | 欧美精品1区2区3区 免费黄篇 | 91在线一区| 一a级片 | 福利电影在线 | 97免费视频在线观看 | 91在线观看 | 四虎影院在线观看av | 孕妇一级毛片 | 91精品国产91久久久久久密臀 | av网站在线播放 | 国产精品国产 | 精品国产一级 | 精品国产一区二区三区性色av | 一本大道久久a久久精二百 国产成人免费在线 | 在线国产一区 | 欧美久久一区二区三区 | 日韩精品极品视频在线观看免费 | 日韩视频在线播放 | 色综合av| 91一区二区 | 福利精品在线观看 | 免费欧美视频 | 日韩一区在线播放 | 五月精品视频 | 日韩网站在线观看 | 精品亚洲一区二区三区 | 伊人春色在线观看 | 午夜伦4480yy私人影院 | 中文字幕免费在线 | 日韩美香港a一级毛片免费 国产综合av | 成人免费视屏 | 久久久久国产一区二区三区 | 天天插天天射天天干 | 国产精品成人一区二区三区吃奶 | 精品国产综合 | 国产欧美在线一区 |