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

高吞吐、線程安全的LRU緩存詳解

 更新時間:2018年02月02日 14:08:44   作者:txxs  
這篇文章主要介紹了高吞吐、線程安全的LRU緩存詳解,分享了相關(guān)代碼示例,小編覺得還是挺不錯的,具有一定借鑒價值,需要的朋友可以參考下

本文研究的主要是高吞吐、線程安全的LRU緩存的相關(guān)內(nèi)容,具體介紹如下。

幾年以前,我實現(xiàn)了一個LRU緩存用來為關(guān)鍵字來查找它的id。數(shù)據(jù)結(jié)構(gòu)非常有意思,因為要求的吞吐很大足以消除大量使用lockssynchronized關(guān)鍵字帶來的性能問題,應(yīng)用是用java實現(xiàn)的。

我想到一連串的原子引用分配會在ConcurrentHashMap中保持LRU保持LRU順序,開始的時候我把value包裝到entry中去,entry在雙鏈表的LRU鏈中有一個節(jié)點,鏈的尾部保持的是最近使用的entry,頭節(jié)點中存放的是當(dāng)緩存達(dá)到一定的大小的時候可能會清空的entry。每一個節(jié)點都指向用來查找的entry。

當(dāng)你通過key查找值的時候,緩存首先要查找map看看是否有這個value存在,如果不存在的話,它將依賴于加載器將value從數(shù)據(jù)源中以read-through的方式讀出來并且以“如果缺失則添加”的方式添加的map中去。確保高吞吐的挑戰(zhàn)是有效的維護LRU鏈。這個并發(fā)的哈希map是分段的而且在線程的水平在一定水平(當(dāng)你構(gòu)建map的時候你可以指定并發(fā)的水平)情況下的時候不會經(jīng)歷太多的線程競爭。但是LRU鏈不能以同樣的方式被劃分嗎,為了解決這個問題,我引入了輔助的隊列用來清除操作。

在cache中有六個基本的方法。對于緩存命中,查找包含兩個基本操作:get和offer,對于換粗丟失包含四個基本的方法get、load、put和offer。在put方法上,我們也許需要追蹤清空操作,在緩存命中的情況下get,我們在LRU鏈上被動的做一些清空叫做凈化操作。

get : lookup entry in the map by key
load : load value from a data source
put : create entry and map it to key
offer: append a node at the tail of the LRU list that refers to a recently accessed entry
evict: remove nodes at the head of the list and associated entries from the map (after the cache reaches a certain size)
purge: delete unused nodes in the LRU list -- we refer to these nodes as holes, and the cleanup queue keeps track of these

清空操作和凈化操作都是大批量的處理數(shù)據(jù),我們來看一下每個操作的細(xì)節(jié)

get操作是按如下方式工作的:

get(K) -> V 
 
lookup entry by key k 
if cache hit, we have an entry e 
  offer entry e 
  try purge some holes 
else 
  load value v for key k 
  create entry e <- (k,v) 
  try put entry e 
end 
return value e.v 

如果key存在,我們在LRU鏈的尾部提供一個新的節(jié)點來表明,這是一個最近使用的值。get和offer的執(zhí)行并不是原子操作(這里沒有l(wèi)ock),所以我們不能說這個offered 節(jié)點指向最近使用的實體,但是肯定是當(dāng)我們并發(fā)執(zhí)行時獲得的最近使用的實體。我們沒有強制get和offer對在線程間執(zhí)行的順序,因為這可能會限制吞吐量。在offer一個節(jié)點之后,我們嘗試著做一些清除和返回value的操作。下邊我們詳細(xì)看一下這offer和purge操作。

如果緩存丟失發(fā)生了,我們將調(diào)用加載器為這個key加載value,創(chuàng)建一個新的實體并把它放入到map中去,put操作如下:

put(E) -> E 
 
existing entry ex <- map.putIfAbsent(e.k, e) 
if absent 
  offer entry e; 
  if size reaches evict-threshold 
    evict some entries 
  end 
  return entry e 
else, we have an existing entry ex 
  return entry ex 
end 

正如你所見的一樣,有兩個或這兩個以上的線程把一個實體放入map的時候可能存在競爭,但是只允許一個成功并且會調(diào)用offer。在LRU鏈的尾部提供一個節(jié)點之后,我們需要檢查是否緩存已經(jīng)達(dá)到了它的闕值的大小,闕值是我們用來出發(fā)批量清空操作的標(biāo)識。在這個特定的應(yīng)用的場景下,闕值的設(shè)置要比容量的大小要小。清空操作小批量的發(fā)生而不是每一個實體加進來的時候都會發(fā)生,多線程或許會參與到清空操作中去,直到緩存的容量達(dá)到它的容量。上鎖很容易但是線程卻能是安全的。清空需要移除LRU鏈的頭節(jié)點,這需要依賴細(xì)心的原子操作來避免在map中多線程的移除操作。

這個offer操作非常有意思,它總是嘗試著創(chuàng)建一個節(jié)點但是并不試圖在LRU中立即移除和刪除那些不再使用的節(jié)點。

offer(E) 
 
if tail node doesn't refer to entry e 
  assign current node c <- e.n 
  create a new node n(e), new node refers to entry e 
  if atomic compare-and-set node e.n, expect c, assign n 
    add node n to tail of LRU list 
    if node c not null 
      set entry c.e to null, c now has a hole 
      add node c to cleanup queue 
    end 
  end 
end 

首先它會檢查,鏈中尾部的節(jié)點沒有指向已經(jīng)訪問的實體,這并沒有什么不同除非所有的線程頻繁的訪問同樣的鍵值對,它將會鏈部的尾的實體創(chuàng)建一個新的節(jié)點當(dāng)這個實體不同的時候,在提供新的節(jié)點之前,它嘗試為實體進一個比較和設(shè)置的操作,這將阻止多線程做同樣的事情。

成功的分配節(jié)點的線程在LRU鏈的尾部提供了一個新的節(jié)點,這個操作和ConcurrentLinkedQueue中的find一樣,依賴的算法在下邊的文章中有描述 Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue Algorithms。線程然后會檢查實體之前是否和其他的節(jié)點有相關(guān)連,如果是這樣的話,老的節(jié)點不會立即刪除,但是會被標(biāo)記為一個hole(它的實體的引用會被設(shè)置為空)

總結(jié)

以上就是本文關(guān)于高吞吐、線程安全的LRU緩存詳解的全部內(nèi)容,希望對大家有所幫助。感興趣的朋友可以繼續(xù)參閱本站其他相關(guān)專題,如有不足之處,歡迎留言指出。感謝朋友們對本站的支持!

相關(guān)文章

  • Java構(gòu)造方法有什么作用?

    Java構(gòu)造方法有什么作用?

    在本篇文章里小編給大家介紹了關(guān)于Java構(gòu)造方法的作用以及相關(guān)的基礎(chǔ)知識點,對此有需要的朋友們可以跟著學(xué)習(xí)下。
    2022-11-11
  • java集合Collection常用方法解讀

    java集合Collection常用方法解讀

    這篇文章主要介紹了java集合Collection常用方法解讀,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • Spring中InitializingBean的使用詳細(xì)解析

    Spring中InitializingBean的使用詳細(xì)解析

    這篇文章主要介紹了Spring中InitializingBean的使用詳細(xì)解析,InitializingBean是Spring提供的拓展性接口,提供了屬性初始化后的處理方法,它只有一個afterPropertiesSet方法,凡是繼承該接口的類,在bean的屬性初始化后都會執(zhí)行該方法,需要的朋友可以參考下
    2024-02-02
  • Spring Boot整合EasyExcel(完整版包含上傳解析excel和下載模板)

    Spring Boot整合EasyExcel(完整版包含上傳解析excel和下載模板)

    這篇文章主要介紹了Spring Boot整合EasyExcel(完整版包含上傳解析excel和下載模板),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • SpringBoot中進行事務(wù)回滾的方法

    SpringBoot中進行事務(wù)回滾的方法

    在Spring Boot中,可以使用TransactionTemplate或@Transactional注解來進行事務(wù)管理,本文主要介紹了SpringBoot中進行事務(wù)回滾的方法,感興趣的可以了解一下
    2023-11-11
  • java 中內(nèi)部類的實例詳解

    java 中內(nèi)部類的實例詳解

    這篇文章主要介紹了java 中內(nèi)部類的實例詳解的相關(guān)資料,希望通過本文能幫助到大家,需要的朋友可以參考下
    2017-09-09
  • Java經(jīng)典面試題最全匯總208道(三)

    Java經(jīng)典面試題最全匯總208道(三)

    這篇文章主要介紹了Java經(jīng)典面試題最全匯總208道(三),本文章內(nèi)容詳細(xì),該模塊分為了六個部分,本次為第三部分,需要的朋友可以參考下
    2023-01-01
  • Java使用OCR技術(shù)識別驗證碼實現(xiàn)自動化登陸方法

    Java使用OCR技術(shù)識別驗證碼實現(xiàn)自動化登陸方法

    在本篇文章里小編給大家分享的是關(guān)于Java 如何使用 OCR 技術(shù)識別驗證碼實現(xiàn)自動化登陸的相關(guān)知識點內(nèi)容,需要的朋友們學(xué)習(xí)下。
    2019-08-08
  • Java注解詳細(xì)介紹

    Java注解詳細(xì)介紹

    這篇文章主要介紹了Java注解詳細(xì)介紹,本文講解了Java注解是什么、Java注解基礎(chǔ)知識、Java注解類型、定義Java注解類型的注意事項等內(nèi)容,需要的朋友可以參考下
    2014-09-09
  • spring boot項目fat jar瘦身的實現(xiàn)

    spring boot項目fat jar瘦身的實現(xiàn)

    這篇文章主要介紹了spring boot項目fat jar瘦身的實現(xiàn),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-06-06

最新評論