欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

GC算法實(shí)現(xiàn)垃圾優(yōu)先算法

 更新時間:2022年01月25日 10:46:48   作者:金色夢想  
為什么會存在那么多的垃圾回收算法呢?我想這個問題的答案可能是沒有任何一種內(nèi)存回收算法是完美的,所以在針對不同的情景需求下,不同的內(nèi)存回收算法有其獨(dú)特的優(yōu)勢,所以最后就延續(xù)了多種回收算法

G1 – Garbage First(垃圾優(yōu)先算法)

G1最主要的設(shè)計(jì)目標(biāo)是: 將STW停頓的時間和分布變成可預(yù)期以及可配置的。事實(shí)上, G1是一款軟實(shí)時垃圾收集器, 也就是說可以為其設(shè)置某項(xiàng)特定的性能指標(biāo). 可以指定: 在任意 xx 毫秒的時間范圍內(nèi), STW停頓不得超過 x 毫秒。 如: 任意1秒暫停時間不得超過5毫秒. Garbage-First GC 會盡力達(dá)成這個目標(biāo)(有很大的概率會滿足, 但并不完全確定,具體是多少將是硬實(shí)時的[hard real-time])。

為了達(dá)成這項(xiàng)指標(biāo), G1 有一些獨(dú)特的實(shí)現(xiàn)。首先, 堆不再分成連續(xù)的年輕代和老年代空間。而是劃分為多個(通常是2048個)可以存放對象的 小堆區(qū)(**aller heap regions)。每個小堆區(qū)都可能是 Eden區(qū), Survivor區(qū)或者Old區(qū). 在邏輯上, 所有的Eden區(qū)和Survivor區(qū)合起來就是年輕代, 所有的Old區(qū)拼在一起那就是老年代:

這樣的劃分使得 GC不必每次都去收集整個堆空間, 而是以增量的方式來處理: 每次只處理一部分小堆區(qū),稱為此次的回收集(collection set). 每次暫停都會收集所有年輕代的小堆區(qū), 但可能只包含一部分老年代小堆區(qū):

G1的另一項(xiàng)創(chuàng)新, 是在并發(fā)階段估算每個小堆區(qū)存活對象的總數(shù)。用來構(gòu)建回收集(collection set)的原則是: 垃圾最多的小堆區(qū)會被優(yōu)先收集。這也是G1名稱的由來: garbage-first。

要啟用G1收集器, 使用的命令行參數(shù)為:

java -XX:+UseG1GC com.mypackages.MyExecutableClass

Evacuation Pause: Fully Young(轉(zhuǎn)移暫停:純年輕代模式)

在應(yīng)用程序剛啟動時, G1還未執(zhí)行過(not-yet-executed)并發(fā)階段, 也就沒有獲得任何額外的信息, 處于初始的 fully-young 模式. 在年輕代空間用滿之后, 應(yīng)用線程被暫停, 年輕代堆區(qū)中的存活對象被復(fù)制到存活區(qū), 如果還沒有存活區(qū),則選擇任意一部分空閑的小堆區(qū)用作存活區(qū)。

復(fù)制的過程稱為轉(zhuǎn)移(Evacuation), 這和前面講過的年輕代收集器基本上是一樣的工作原理。轉(zhuǎn)移暫停的日志信息很長,為簡單起見, 我們?nèi)コ艘恍┎恢匾男畔? 在并發(fā)階段之后我們會進(jìn)行詳細(xì)的講解。此外, 由于日志記錄很多, 所以并行階段和“其他”階段的日志將拆分為多個部分來進(jìn)行講解:

0.134: [GC pause (G1 Evacuation Pause) (young), 0.0144119 secs]
[Parallel Time: 13.9 ms, GC Workers: 8]
…
[Code Root Fixup: 0.0 ms]
[Code Root Purge: 0.0 ms]
[Clear CT: 0.1 ms]
[Other: 0.4 ms] …
[Eden: 24.0M(24.0M)->0.0B(13.0M) Survivors: 0.0B->3072.0K Heap: 24.0M(256.0M)->21.9M(256.0M)] [Times: user=0.04 sys=0.04, real=0.02 secs]

>

0.134: [GC pause (G1 Evacuation Pause) (young), 0.0144119 secs] – G1轉(zhuǎn)移暫停,只清理年輕代空間。暫停在JVM啟動之后 134 ms 開始, 持續(xù)的系統(tǒng)時間為 0.0144秒 。

[Parallel Time: 13.9 ms, GC Workers: 8] – 表明后面的活動由8個 Worker 線程并行執(zhí)行, 消耗時間為13.9毫秒(real time)。

 – 為閱讀方便, 省略了部分內(nèi)容,請參考后文。

[Code Root Fixup: 0.0 ms] – 釋放用于管理并行活動的內(nèi)部數(shù)據(jù)。一般都接近于零。這是串行執(zhí)行的過程。

[Code Root Purge: 0.0 ms] – 清理其他部分?jǐn)?shù)據(jù), 也是非??斓? 但如非必要則幾乎等于零。這是串行執(zhí)行的過程。

[Other: 0.4 ms] – 其他活動消耗的時間, 其中有很多是并行執(zhí)行的。

 – 請參考后文。

[Eden: 24.0M(24.0M)->0.0B(13.0M) – 暫停之前和暫停之后, Eden 區(qū)的使用量/總?cè)萘俊?/p>

Survivors: 0.0B->3072.0K – 暫停之前和暫停之后, 存活區(qū)的使用量。

Heap: 24.0M(256.0M)->21.9M(256.0M)] – 暫停之前和暫停之后, 整個堆內(nèi)存的使用量與總?cè)萘俊?/p>

[Times: user=0.04 sys=0.04, real=0.02 secs] – GC事件的持續(xù)時間, 通過三個部分來衡量:

  • user – 在此次垃圾回收過程中, 由GC線程所消耗的總的CPU時間。
  • sys – GC過程中, 系統(tǒng)調(diào)用和系統(tǒng)等待事件所消耗的時間。
  • real – 應(yīng)用程序暫停的時間。在并行GC(Parallel GC)中, 這個數(shù)字約等于: (user time + system time)/GC線程數(shù)。 這里使用的是8個線程。 請注意,總是有一定比例的處理過程是不能并行化的。

說明: 系統(tǒng)時間(wall clock time, elapsed time), 是指一段程序從運(yùn)行到終止,系統(tǒng)時鐘走過的時間。一般來說,系統(tǒng)時間都是要大于CPU時間

最繁重的GC任務(wù)由多個專用的 worker 線程來執(zhí)行。下面的日志描述了他們的行為:

[Parallel Time: 13.9 ms, GC Workers: 8]
[GC Worker Start (ms): Min: 134.0, Avg: 134.1, Max: 134.1, Diff: 0.1]
[Ext Root Scanning (ms): Min: 0.1, Avg: 0.2, Max: 0.3, Diff: 0.2, Sum: 1.2]
[Update RS (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
[Processed Buffers: Min: 0, Avg: 0.0, Max: 0, Diff: 0, Sum: 0]
[Scan RS (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.0]
[Code Root Scanning (ms): Min: 0.0, Avg: 0.0, Max: 0.2, Diff: 0.2, Sum: 0.2]
[Object Copy (ms): Min: 10.8, Avg: 12.1, Max: 12.6, Diff: 1.9, Sum: 96.5]
[Termination (ms): Min: 0.8, Avg: 1.5, Max: 2.8, Diff: 1.9, Sum: 12.2]
[Termination Attempts: Min: 173, Avg: 293.2, Max: 362, Diff: 189, Sum: 2346]
[GC Worker Other (ms): Min: 0.0, Avg: 0.0, Max: 0.0, Diff: 0.0, Sum: 0.1]
GC Worker Total (ms): Min: 13.7, Avg: 13.8, Max: 13.8, Diff: 0.1, Sum: 110.2]
[GC Worker End (ms): Min: 147.8, Avg: 147.8, Max: 147.8, Diff: 0.0]

[Parallel Time: 13.9 ms, GC Workers: 8] – 表明下列活動由8個線程并行執(zhí)行,消耗的時間為13.9毫秒(real time)。

[GC Worker Start (ms) – GC的worker線程開始啟動時,相對于 pause 開始的時間戳。如果 Min 和 Max 差別很大,則表明本機(jī)其他進(jìn)程所使用的線程數(shù)量過多, 擠占了GC的CPU時間。

[Ext Root Scanning (ms) – 用了多長時間來掃描堆外(non-heap)的root, 如 classloaders, JNI引用, JVM的系統(tǒng)root等。后面顯示了運(yùn)行時間, “Sum” 指的是CPU時間。

[Code Root Scanning (ms) – 用了多長時間來掃描實(shí)際代碼中的 root: 例如局部變量等等(local vars)。

[Object Copy (ms) – 用了多長時間來拷貝收集區(qū)內(nèi)的存活對象。

[Termination (ms) – GC的worker線程用了多長時間來確保自身可以安全地停止, 這段時間什么也不用做, stop 之后該線程就終止運(yùn)行了。

[Termination Attempts – GC的worker 線程嘗試多少次 try 和 teminate。如果worker發(fā)現(xiàn)還有一些任務(wù)沒處理完,則這一次嘗試就是失敗的, 暫時還不能終止。

[GC Worker Other (ms) – 一些瑣碎的小活動,在GC日志中不值得單獨(dú)列出來。

GC Worker Total (ms) – GC的worker 線程的工作時間總計(jì)。

[GC Worker End (ms) – GC的worker 線程完成作業(yè)的時間戳。通常來說這部分?jǐn)?shù)字應(yīng)該大致相等, 否則就說明有太多的線程被掛起, 很可能是因?yàn)?a rel="external nofollow" target="_blank">壞鄰居效應(yīng)(noisy neighbor) 所導(dǎo)致的。

此外,在轉(zhuǎn)移暫停期間,還有一些瑣碎執(zhí)行的小活動。這里我們只介紹其中的一部分, 其余的會在后面進(jìn)行討論。

[Other: 0.4 ms]
[Choose CSet: 0.0 ms]
[Ref Proc: 0.2 ms]
[Ref Enq: 0.0 ms]
[Redirty Cards: 0.1 ms]
[Humongous Register: 0.0 ms]
[Humongous Reclaim: 0.0 ms]
[Free CSet: 0.0 ms]

[Other: 0.4 ms] – 其他活動消耗的時間, 其中有很多也是并行執(zhí)行的。

[Ref Proc: 0.2 ms] – 處理非強(qiáng)引用(non-strong)的時間: 進(jìn)行清理或者決定是否需要清理。

[Ref Enq: 0.0 ms] – 用來將剩下的 non-strong 引用排列到合適的 ReferenceQueue中。

[Free CSet: 0.0 ms] – 將回收集中被釋放的小堆歸還所消耗的時間, 以便他們能用來分配新的對象。

Concurrent Marking(并發(fā)標(biāo)記)

G1收集器的很多概念建立在CMS的基礎(chǔ)上,所以下面的內(nèi)容需要你對CMS有一定的理解. 雖然也有很多地方不同, 但并發(fā)標(biāo)記的目標(biāo)基本上是一樣的. G1的并發(fā)標(biāo)記通過 Snapshot-At-The-Beginning(開始時快照) 的方式, 在標(biāo)記階段開始時記下所有的存活對象。即使在標(biāo)記的同時又有一些變成了垃圾. 通過對象是存活信息, 可以構(gòu)建出每個小堆區(qū)的存活狀態(tài), 以便回收集能高效地進(jìn)行選擇。

這些信息在接下來的階段會用來執(zhí)行老年代區(qū)域的垃圾收集。在兩種情況下是完全地并發(fā)執(zhí)行的: 一、如果在標(biāo)記階段確定某個小堆區(qū)只包含垃圾; 二、在STW轉(zhuǎn)移暫停期間, 同時包含垃圾和存活對象的老年代小堆區(qū)。

當(dāng)堆內(nèi)存的總體使用比例達(dá)到一定數(shù)值時,就會觸發(fā)并發(fā)標(biāo)記。默認(rèn)值為 45%, 但也可以通過JVM參數(shù) InitiatingHeapOccupancyPercent 來設(shè)置。和CMS一樣, G1的并發(fā)標(biāo)記也是由多個階段組成, 其中一些是完全并發(fā)的, 還有一些階段需要暫停應(yīng)用線程。

階段 1: Initial Mark(初始標(biāo)記)。 此階段標(biāo)記所有從GC root 直接可達(dá)的對象。在CMS中需要一次STW暫停, 但G1里面通常是在轉(zhuǎn)移暫停的同時處理這些事情, 所以它的開銷是很小的. 可以在 Evacuation Pause 日志中的第一行看到(initial-mark)暫停:

1.631: [GC pause (G1 Evacuation Pause) (young) (initial-mark), 0.0062656 secs]

階段 2: Root Region Scan(Root區(qū)掃描). 此階段標(biāo)記所有從 “根區(qū)域” 可達(dá)的存活對象。 根區(qū)域包括: 非空的區(qū)域, 以及在標(biāo)記過程中不得不收集的區(qū)域。因?yàn)樵诓l(fā)標(biāo)記的過程中遷移對象會造成很多麻煩, 所以此階段必須在下一次轉(zhuǎn)移暫停之前完成。如果必須啟動轉(zhuǎn)移暫停, 則會先要求根區(qū)域掃描中止, 等它完成才能繼續(xù)掃描. 在當(dāng)前版本的實(shí)現(xiàn)中, 根區(qū)域是存活的小堆區(qū): y包括下一次轉(zhuǎn)移暫停中肯定會被清理的那部分年輕代小堆區(qū)。

1.362: [GC concurrent-root-region-scan-start]
1.364: [GC concurrent-root-region-scan-end, 0.0028513 secs]

階段 3: Concurrent Mark(并發(fā)標(biāo)記). 此階段非常類似于CMS: 它只是遍歷對象圖, 并在一個特殊的位圖中標(biāo)記能訪問到的對象. 為了確保標(biāo)記開始時的快照準(zhǔn)確性, 所有應(yīng)用線程并發(fā)對對象圖執(zhí)行的引用更新,G1 要求放棄前面階段為了標(biāo)記目的而引用的過時引用。

這是通過使用 Pre-Write 屏障來實(shí)現(xiàn)的,(不要和之后介紹的 Post-Write 混淆, 也不要和多線程開發(fā)中的內(nèi)存屏障(memory barriers)相混淆)。Pre-Write屏障的作用是: G1在進(jìn)行并發(fā)標(biāo)記時, 如果程序?qū)ο蟮哪硞€屬性做了變更, 就會在 log buffers 中存儲之前的引用。 由并發(fā)標(biāo)記線程負(fù)責(zé)處理。

1.364: [GC concurrent-mark-start]
1.645: [GC co ncurrent-mark-end, 0.2803470 secs]

階段 4: Remark(再次標(biāo)記). 和CMS類似,這也是一次STW停頓,以完成標(biāo)記過程。對于G1,它短暫地停止應(yīng)用線程, 停止并發(fā)更新日志的寫入, 處理其中的少量信息, 并標(biāo)記所有在并發(fā)標(biāo)記開始時未被標(biāo)記的存活對象。這一階段也執(zhí)行某些額外的清理, 如引用處理(參見 Evacuation Pause log) 或者類卸載(class unloading)。

1.645: [GC remark 1.645: [Finalize Marking, 0.0009461 secs]
1.646: [GC ref-proc, 0.0000417 secs] 1.646:
[Unloading, 0.0011301 secs], 0.0074056 secs]
[Times: user=0.01 sys=0.00, real=0.01 secs]

階段 5: Cleanup(清理). 最后這個小階段為即將到來的轉(zhuǎn)移階段做準(zhǔn)備, 統(tǒng)計(jì)小堆區(qū)中所有存活的對象, 并將小堆區(qū)進(jìn)行排序, 以提升GC的效率. 此階段也為下一次標(biāo)記執(zhí)行所有必需的整理工作(house-keeping activities): 維護(hù)并發(fā)標(biāo)記的內(nèi)部狀態(tài)。

最后要提醒的是, 所有不包含存活對象的小堆區(qū)在此階段都被回收了。有一部分是并發(fā)的: 例如空堆區(qū)的回收,還有大部分的存活率計(jì)算, 此階段也需要一個短暫的STW暫停, 以不受應(yīng)用線程的影響來完成作業(yè). 這種STW停頓的日志如下:

1.652: [GC cleanup 1213M->1213M(1885M), 0.0030492 secs]
[Times: user=0.01 sys=0.00, real=0.00 secs]

如果發(fā)現(xiàn)某些小堆區(qū)中只包含垃圾, 則日志格式可能會有點(diǎn)不同, 如:?
1.872: [GC cleanup 1357M->173M(1996M), 0.0015664 secs] [Times: user=0.01 sys=0.00, real=0.01 secs] 1.874: [GC concurrent-cleanup-start] 1.876: [GC concurrent-cleanup-end, 0.0014846 secs]

Evacuation Pause: Mixed (轉(zhuǎn)移暫停: 混合模式)

能并發(fā)清理老年代中整個整個的小堆區(qū)是一種最優(yōu)情形, 但有時候并不是這樣。并發(fā)標(biāo)記完成之后, G1將執(zhí)行一次混合收集(mixed collection), 不只清理年輕代, 還將一部分老年代區(qū)域也加入到 collection set 中。

混合模式的轉(zhuǎn)移暫停(Evacuation pause)不一定緊跟著并發(fā)標(biāo)記階段。有很多規(guī)則和歷史數(shù)據(jù)會影響混合模式的啟動時機(jī)。比如, 假若在老年代中可以并發(fā)地騰出很多的小堆區(qū),就沒有必要啟動混合模式。

因此, 在并發(fā)標(biāo)記與混合轉(zhuǎn)移暫停之間, 很可能會存在多次 fully-young 轉(zhuǎn)移暫停。

添加到回收集的老年代小堆區(qū)的具體數(shù)字及其順序, 也是基于許多規(guī)則來判定的。 其中包括指定的軟實(shí)時性能指標(biāo), 存活性,以及在并發(fā)標(biāo)記期間收集的GC效率等數(shù)據(jù), 外加一些可配置的JVM選項(xiàng). 混合收集的過程, 很大程度上和前面的 fully-young gc 是一樣的, 但這里我們還要介紹一個概念: remembered sets(歷史記憶集)。

Remembered sets (歷史記憶集)是用來支持不同的小堆區(qū)進(jìn)行獨(dú)立回收的。例如,在收集A、B、C區(qū)時, 我們必須要知道是否有從D區(qū)或者E區(qū)指向其中的引用, 以確定他們的存活性. 但是遍歷整個堆需要相當(dāng)長的時間, 這就違背了增量收集的初衷, 因此必須采取某種優(yōu)化手段. 其他GC算法有獨(dú)立的 Card Table 來支持年輕代的垃圾收集一樣, 而G1中使用的是 Remembered Sets。

如下圖所示, 每個小堆區(qū)都有一個 remembered set, 列出了從外部指向本區(qū)的所有引用。這些引用將被視為附加的 GC root. 注意,在并發(fā)標(biāo)記過程中,老年代中被確定為垃圾的對象會被忽略, 即使有外部引用指向他們: 因?yàn)樵谶@種情況下引用者也是垃圾。

接下來的行為,和其他垃圾收集器一樣: 多個GC線程并行地找出哪些是存活對象,確定哪些是垃圾:

最后, 存活對象被轉(zhuǎn)移到存活區(qū)(survivor regions), 在必要時會創(chuàng)建新的小堆區(qū)?,F(xiàn)在,空的小堆區(qū)被釋放, 可用于存放新的對象了。

為了維護(hù) remembered set, 在程序運(yùn)行的過程中, 只要寫入某個字段,就會產(chǎn)生一個 Post-Write 屏障。如果生成的引用是跨區(qū)域的(cross-region),即從一個區(qū)指向另一個區(qū), 就會在目標(biāo)區(qū)的Remembered Set中,出現(xiàn)一個對應(yīng)的條目。為了減少 Write Barrier 造成的開銷, 將卡片放入Remembered Set 的過程是異步的, 而且經(jīng)過了很多的優(yōu)化. 總體上是這樣: Write Barrier 把臟卡信息存放到本地緩沖區(qū)(local buffer), 有專門的GC線程負(fù)責(zé)收集, 并將相關(guān)信息傳給被引用區(qū)的 remembered set。

混合模式下的日志, 和純年輕代模式相比, 可以發(fā)現(xiàn)一些有趣的地方:

[[Update RS (ms): Min: 0.7, Avg: 0.8, Max: 0.9, Diff: 0.2, Sum: 6.1]
[Processed Buffers: Min: 0, Avg: 2.2, Max: 5, Diff: 5, Sum: 18]
[Scan RS (ms): Min: 0.0, Avg: 0.1, Max: 0.2, Diff: 0.2, Sum: 0.8]
[Clear CT: 0.2 ms]
[Redirty Cards: 0.1 ms]

[Update RS (ms) – 因?yàn)?Remembered Sets 是并發(fā)處理的,必須確保在實(shí)際的垃圾收集之前, 緩沖區(qū)中的 card 得到處理。如果card數(shù)量很多, 則GC并發(fā)線程的負(fù)載可能就會很高??赡艿脑蚴? 修改的字段過多, 或者CPU資源受限。

[Processed Buffers – 每個 worker 線程處理了多少個本地緩沖區(qū)(local buffer)。

[Scan RS (ms) – 用了多長時間掃描來自RSet的引用。

[Clear CT: 0.2 ms] – 清理 card table 中 cards 的時間。清理工作只是簡單地刪除“臟”狀態(tài), 此狀態(tài)用來標(biāo)識一個字段是否被更新的, 供Remembered Sets使用。

[Redirty Cards: 0.1 ms] – 將 card table 中適當(dāng)?shù)奈恢脴?biāo)記為 dirty 所花費(fèi)的時間。”適當(dāng)?shù)奈恢?rdquo;是由GC本身執(zhí)行的堆內(nèi)存改變所決定的, 例如引用排隊(duì)等。

總結(jié)

通過本節(jié)內(nèi)容的學(xué)習(xí), 你應(yīng)該對G1垃圾收集器有了一定了解。當(dāng)然, 為了簡潔, 我們省略了很多實(shí)現(xiàn)細(xì)節(jié), 例如如何處理巨無霸對象(humongous objects)。 綜合來看, G1是HotSpot中最先進(jìn)的準(zhǔn)產(chǎn)品級(production-ready)垃圾收集器。重要的是, HotSpot 工程師的主要精力都放在不斷改進(jìn)G1上面, 在新的java版本中,將會帶來新的功能和優(yōu)化。

可以看到, G1 解決了 CMS 中的各種疑難問題, 包括暫停時間的可預(yù)測性, 并終結(jié)了堆內(nèi)存的碎片化。對單業(yè)務(wù)延遲非常敏感的系統(tǒng)來說, 如果CPU資源不受限制,那么G1可以說是 HotSpot 中最好的選擇, 特別是在最新版本的Java虛擬機(jī)中。當(dāng)然,這種降低延遲的優(yōu)化也不是沒有代價的: 由于額外的寫屏障(write barriers)和更積極的守護(hù)線程, G1的開銷會更大。所以, 如果系統(tǒng)屬于吞吐量優(yōu)先型的, 又或者CPU持續(xù)占用100%, 而又不在乎單次GC的暫停時間, 那么CMS是更好的選擇。

總之: G1適合大內(nèi)存,需要低延遲的場景。

選擇正確的GC算法,唯一可行的方式就是去嘗試,并找出不對勁的地方, 在下一章我們將給出一般指導(dǎo)原則。

注意,G1可能會成為Java 9的默認(rèn)GC: http://openjdk.java.net/jeps/248

以上就是GC算法實(shí)現(xiàn)垃圾優(yōu)先算法的詳細(xì)內(nèi)容,更多關(guān)于GC垃圾優(yōu)先算法的資料請關(guān)注腳本之家其它相關(guān)文章!

原文鏈接:https://plumbr.io/handbook/garbage-collection-algorithms-implementations#g1

相關(guān)文章

  • Aspectj與Spring AOP的對比分析

    Aspectj與Spring AOP的對比分析

    這篇文章主要介紹了Aspectj與Spring AOP的對比分析,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • Java方法重載和方法重寫的區(qū)別到底在哪?

    Java方法重載和方法重寫的區(qū)別到底在哪?

    今天給大家?guī)淼氖顷P(guān)于Java的相關(guān)知識,文章圍繞著Java方法重載和方法重寫的區(qū)別到底在哪展開,文中有非常詳細(xì)的解釋,需要的朋友可以參考下
    2021-06-06
  • Java中的LinkedHashMap詳解

    Java中的LinkedHashMap詳解

    這篇文章主要介紹了Java中的LinkedHashMap詳解,LinkedHashMap繼承自HashMap,它的多種操作都是建立在HashMap操作的基礎(chǔ)上的,同HashMap不同的是,LinkedHashMap維護(hù)了一個Entry的雙向鏈表,保證了插入的Entry中的順序,需要的朋友可以參考下
    2023-09-09
  • springBoot接入阿里云oss的實(shí)現(xiàn)步驟

    springBoot接入阿里云oss的實(shí)現(xiàn)步驟

    這篇文章主要介紹了springBoot接入阿里云oss的實(shí)現(xiàn)步驟,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • Java使用線程同步解決線程安全問題詳解

    Java使用線程同步解決線程安全問題詳解

    線程安全是多線程編程時的計(jì)算機(jī)程序代碼中的一個概念。在擁有共享數(shù)據(jù)的多條線程并行執(zhí)行的程序中,線程安全的代碼會通過同步機(jī)制保證各個線程都可以正常且正確的執(zhí)行,不會出現(xiàn)數(shù)據(jù)污染等意外情況
    2022-05-05
  • java 多態(tài)與抽象類詳解總結(jié)

    java 多態(tài)與抽象類詳解總結(jié)

    在面向?qū)ο蟮母拍钪?,所有的對象都是通過類來描繪的,但是反過來,并不是所有的類都是用來描繪對象的,如果一個類中沒有包含足夠的信息來描繪一個具體的對象,這樣的類就是抽象類,而多態(tài)是同一個行為具有多個不同表現(xiàn)形式或形態(tài)的能力
    2021-11-11
  • Log4j.properties配置及其使用

    Log4j.properties配置及其使用

    本文主要介紹了Log4j.properties配置及其使用,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • Spring MVC 攔截器實(shí)現(xiàn)代碼

    Spring MVC 攔截器實(shí)現(xiàn)代碼

    本篇文章主要介紹了Spring MVC 攔截器的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下。
    2017-02-02
  • Java內(nèi)存模型之重排序的相關(guān)知識總結(jié)

    Java內(nèi)存模型之重排序的相關(guān)知識總結(jié)

    重排序是指編譯器和處理器為了優(yōu)化性能而對指令序列進(jìn)行重新排序的一種手段,文中詳細(xì)介紹了Java重排序的相關(guān)知識,需要的朋友可以參考下
    2021-06-06
  • IDEA中關(guān)于enter鍵換行的問題

    IDEA中關(guān)于enter鍵換行的問題

    這篇文章主要介紹了IDEA中關(guān)于enter鍵換行的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-06-06

最新評論