日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Google 出的 Guava 是个什么鬼

發布時間:2023/12/3 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Google 出的 Guava 是个什么鬼 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉載自? ?Google 出的 Guava 是個什么鬼

前言

Google 出的?Guava?是 Java 核心增強的庫,應用非常廣泛。

我平時用的也挺頻繁,這次就借助日常使用的 Cache 組件來看看 Google 大牛們是如何設計的。

緩存

本次主要討論緩存。

緩存在日常開發中舉足輕重,如果你的應用對某類數據有著較高的讀取頻次,并且改動較小時那就非常適合利用緩存來提高性能。

緩存之所以可以提高性能是因為它的讀取效率很高,就像是 CPU 的?L1、L2、L3?緩存一樣,級別越高相應的讀取速度也會越快。

但也不是什么好處都占,讀取速度快了但是它的內存更小資源更寶貴,所以我們應當緩存真正需要的數據。

其實也就是典型的空間換時間。

下面談談 Java 中所用到的緩存。

JVM 緩存

首先是 JVM 緩存,也可以認為是堆緩存。

其實就是創建一些全局變量,如?Map、List?之類的容器用于存放數據。

這樣的優勢是使用簡單但是也有以下問題:

  • 只能顯式的寫入,清除數據。

  • 不能按照一定的規則淘汰數據,如?LRU,LFU,FIFO?等。

  • 清除數據時的回調通知。

  • 其他一些定制功能等。

Ehcache、Guava Cache

所以出現了一些專門用作 JVM 緩存的開源工具出現了,如本文提到的 Guava Cache。

它具有上文 JVM 緩存不具有的功能,如自動清除數據、多種清除算法、清除回調等。

但也正因為有了這些功能,這樣的緩存必然會多出許多東西需要額外維護,自然也就增加了系統的消耗。

分布式緩存

剛才提到的兩種緩存其實都是堆內緩存,只能在單個節點中使用,這樣在分布式場景下就招架不住了。

于是也有了一些緩存中間件,如 Redis、Memcached,在分布式環境下可以共享內存。

具體不在本次的討論范圍。

Guava Cache 示例

之所以想到 Guava 的 Cache,也是最近在做一個需求,大體如下:

從 Kafka 實時讀取出應用系統的日志信息,該日志信息包含了應用的健康狀況。 如果在時間窗口 N 內發生了 X 次異常信息,相應的我就需要作出反饋(報警、記錄日志等)。

對此 Guava 的 Cache 就非常適合,我利用了它的 N 個時間內不寫入數據時緩存就清空的特點,在每次讀取數據時判斷異常信息是否大于 X 即可。

偽代碼如下:

首先是構建了 LoadingCache 對象,在 N 分鐘內不寫入數據時就回收緩存(當通過 Key 獲取不到緩存時,默認返回 0)。

然后在每次消費時候調用?checkAlert()?方法進行校驗,這樣就可以達到上文的需求。

我們來設想下 Guava 它是如何實現過期自動清除數據,并且是可以按照 LRU 這樣的方式清除的。

大膽假設下:

內部通過一個隊列來維護緩存的順序,每次訪問過的數據移動到隊列頭部,并且額外開啟一個線程來判斷數據是否過期,過期就刪掉。有點類似于我之前寫過的?動手實現一個 LRU cache

胡適說過:大膽假設小心論證

下面來看看 Guava 到底是怎么實現。

原理分析

看原理最好不過是跟代碼一步步走了:

示例代碼在這里:

https://github.com/crossoverJie/Java-Interview/blob/master/src/main/java/com/crossoverjie/guava/CacheLoaderTest.java

為了能看出 Guava 是怎么刪除過期數據的在獲取緩存之前休眠了 5 秒鐘,達到了超時條件。

最終會發現在?com.google.common.cache.LocalCache?類的 2187 行比較關鍵。

再跟進去之前第 2182 行會發現先要判斷 count 是否大于 0,這個 count 保存的是當前緩存的數量,并用 volatile 修飾保證了可見性。

更多關于 volatile 的相關信息可以查看?你應該知道的 volatile 關鍵字

接著往下跟到:

2761 行,根據方法名稱可以看出是判斷當前的 Entry 是否過期,該 entry 就是通過 key 查詢到的。

這里就很明顯的看出是根據根據構建時指定的過期方式來判斷當前 key 是否過期了。

如果過期就往下走,嘗試進行過期刪除(需要加鎖,后面會具體討論)。

到了這里也很清晰了:

  • 獲取當前緩存的總數量

  • 自減一(前面獲取了鎖,所以線程安全)

  • 刪除并將更新的總數賦值到 count。

其實大體上就是這個流程,Guava 并沒有按照之前猜想的另起一個線程來維護過期數據。

應該是以下原因:

  • 新起線程需要資源消耗。

  • 維護過期數據還要獲取額外的鎖,增加了消耗。

而在查詢時候順帶做了這些事情,但是如果該緩存遲遲沒有訪問也會存在數據不能被回收的情況,不過這對于一個高吞吐的應用來說也不是問題。

總結

最后再來總結下 Guava 的 Cache。

其實在上文跟代碼時會發現通過一個 key 定位數據時有以下代碼:

如果有看過?ConcurrentHashMap 的原理?應該會想到這其實非常類似。

其實 Guava Cache 為了滿足并發場景的使用,核心的數據結構就是按照 ConcurrentHashMap 來的,這里也是一個 key 定位到一個具體位置的過程。

先找到 Segment,再找具體的位置,等于是做了兩次 Hash 定位。

上文有一個假設是對的,它內部會維護兩個隊列?accessQueue,writeQueue?用于記錄緩存順序,這樣才可以按照順序淘汰數據(類似于利用 LinkedHashMap 來做 LRU 緩存)。

同時從上文的構建方式來看,它也是構建者模式來創建對象的。

因為作為一個給開發者使用的工具,需要有很多的自定義屬性,利用構建則模式再合適不過了。

Guava 其實還有很多東西沒談到,比如它利用 GC 來回收內存,移除數據時的回調通知等。之后再接著討論。

總結

以上是生活随笔為你收集整理的Google 出的 Guava 是个什么鬼的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。