国产睡熟迷奷白丝护士系列精品,中文色字幕网站,免费h网站在线观看的,亚洲开心激情在线

      <sup id="hb9fh"></sup>
          1. 千鋒教育-做有情懷、有良心、有品質(zhì)的職業(yè)教育機(jī)構(gòu)

            手機(jī)站
            千鋒教育

            千鋒學(xué)習(xí)站 | 隨時隨地免費(fèi)學(xué)

            千鋒教育

            掃一掃進(jìn)入千鋒手機(jī)站

            領(lǐng)取全套視頻
            千鋒教育

            關(guān)注千鋒學(xué)習(xí)站小程序
            隨時隨地免費(fèi)學(xué)習(xí)課程

            當(dāng)前位置:首頁  >  技術(shù)干貨  > 千鋒Java培訓(xùn)分享如何設(shè)計(jì)一個本地緩存

            千鋒Java培訓(xùn)分享如何設(shè)計(jì)一個本地緩存

            來源:千鋒教育
            發(fā)布人:劉老師
            時間: 2020-07-08 18:05:00 1594202700

            前言

            最近在看Mybatis的源碼,剛好看到緩存這一塊,Mybatis提供了一級緩存和二級緩存;一級緩存相對來說比較簡單,功能比較齊全的是二級緩存,基本上滿足了一個緩存該有的功能;當(dāng)然如果拿來和專門的緩存框架如ehcache來對比可能稍有差距;本文千鋒Java培訓(xùn)講師帶大家來整理一下實(shí)現(xiàn)一個本地緩存都應(yīng)該需要考慮哪些東西。

            考慮點(diǎn)

            考慮點(diǎn)主要在數(shù)據(jù)用何種方式存儲,能存儲多少數(shù)據(jù),多余的數(shù)據(jù)如何處理等幾個點(diǎn),下面我們來詳細(xì)的介紹每個考慮點(diǎn),以及該如何去實(shí)現(xiàn);

            1.數(shù)據(jù)結(jié)構(gòu)

            首要考慮的就是數(shù)據(jù)該如何存儲,用什么數(shù)據(jù)結(jié)構(gòu)存儲,最簡單的就直接用Map來存儲數(shù)據(jù);或者復(fù)雜的如redis一樣提供了多種數(shù)據(jù)類型哈希,列表,集合,有序集合等,底層使用了雙端鏈表,壓縮列表,集合,跳躍表等數(shù)據(jù)結(jié)構(gòu);

            2.對象上限

            因?yàn)槭潜镜鼐彺?,?nèi)存有上限,所以一般都會指定緩存對象的數(shù)量比如1024,當(dāng)達(dá)到某個上限后需要有某種策略去刪除多余的數(shù)據(jù);

            3.清除策略

            上面說到當(dāng)達(dá)到對象上限之后需要有清除策略,常見的比如有LRU(最近最少使用)、FIFO(先進(jìn)先出)、LFU(最近最不常用)、SOFT(軟引用)、WEAK(弱引用)等策略;

            4.過期時間

            除了使用清除策略,一般本地緩存也會有一個過期時間設(shè)置,比如redis可以給每個key設(shè)置一個過期時間,這樣當(dāng)達(dá)到過期時間之后直接刪除,采用清除策略+過期時間雙重保證;

            5.線程安全

            像redis是直接使用單線程處理,所以就不存在線程安全問題;而我們現(xiàn)在提供的本地緩存往往是可以多個線程同時訪問的,所以線程安全是不容忽視的問題;并且線程安全問題是不應(yīng)該拋給使用者去保證;

            6.簡明的接口

            提供一個傻瓜式的對外接口是很有必要的,對使用者來說使用此緩存不是一種負(fù)擔(dān)而是一種享受;提供常用的get,put,remove,clear,getSize方法即可;

            7.是否持久化

            這個其實(shí)不是必須的,是否需要將緩存數(shù)據(jù)持久化看需求;本地緩存如ehcache是支持持久化的,而guava是沒有持久化功能的;分布式緩存如redis是有持久化功能的,memcached是沒有持久化功能的;

            8.阻塞機(jī)制

            在看Mybatis源碼的時候,二級緩存提供了一個blocking標(biāo)識,表示當(dāng)在緩存中找不到元素時,它設(shè)置對緩存鍵的鎖定;這樣其他線程將等待此元素被填充,而不是命中數(shù)據(jù)庫;其實(shí)我們使用緩存的目的就是因?yàn)楸痪彺娴臄?shù)據(jù)生成比較費(fèi)時,比如調(diào)用對外的接口,查詢數(shù)據(jù)庫,計(jì)算量很大的結(jié)果等等;這時候如果多個線程同時調(diào)用get方法獲取的結(jié)果都為null,每個線程都去執(zhí)行一遍費(fèi)時的計(jì)算,其實(shí)也是對資源的浪費(fèi);比較好的辦法是只有一個線程去執(zhí)行,其他線程等待,計(jì)算一次就夠了;但是此功能基本上都交給使用者來處理,很少有本地緩存有這種功能;

            如何實(shí)現(xiàn)

            以上大致介紹了實(shí)現(xiàn)一個本地緩存我們都有哪些需要考慮的地方,當(dāng)然可能還有其他沒有考慮到的點(diǎn);下面繼續(xù)看看關(guān)于每個點(diǎn)都應(yīng)該如何去實(shí)現(xiàn),重點(diǎn)介紹一下思路;

            1.數(shù)據(jù)結(jié)構(gòu)

            本地緩存最常見的是直接使用Map來存儲,比如guava使用ConcurrentHashMap,ehcache也是用了ConcurrentHashMap,Mybatis二級緩存使用HashMap來存儲:

            Map<Object, Object> cache = new ConcurrentHashMap<Object, Object>()

            Mybatis使用HashMap本身是非線程安全的,所以可以看到起內(nèi)部使用了一個SynchronizedCache用來包裝,保證線程的安全性;

            當(dāng)然除了使用Map來存儲,可能還使用其他數(shù)據(jù)結(jié)構(gòu)來存儲,比如redis使用了雙端鏈表,壓縮列表,整數(shù)集合,跳躍表和字典;當(dāng)然這主要是因?yàn)閞edis對外提供的接口很豐富除了哈希還有列表,集合,有序集合等功能;

            2.對象上限

            本地緩存常見的一個屬性,一般緩存都會有一個默認(rèn)值比如1024,在用戶沒有指定的情況下默認(rèn)指定;當(dāng)緩存的數(shù)據(jù)達(dá)到指定最大值時,需要有相關(guān)策略從緩存中清除多余的數(shù)據(jù)這就涉及到下面要介紹的清除策略;

            3.清除策略

            配合對象上限之后使用,場景的清除策略如:LRU(最近最少使用)、FIFO(先進(jìn)先出)、LFU(最近最不常用)、SOFT(軟引用)、WEAK(弱引用);

            LRU:Least Recently Used的縮寫最近最少使用,移除最長時間不被使用的對象;常見的使用LinkedHashMap來實(shí)現(xiàn),也是很多本地緩存默認(rèn)使用的策略;

            FIFO:先進(jìn)先出,按對象進(jìn)入緩存的順序來移除它們;常見使用隊(duì)列Queue來實(shí)現(xiàn);

            LFU:Least Frequently Used的縮寫大概也是最近最少使用的意思,和LRU有點(diǎn)像;區(qū)別點(diǎn)在LRU的淘汰規(guī)則是基于訪問時間,而LFU是基于訪問次數(shù)的;可以通過HashMap并且記錄訪問次數(shù)來實(shí)現(xiàn);

            SOFT:軟引用基于垃圾回收器狀態(tài)和軟引用規(guī)則移除對象;常見使用SoftReference來實(shí)現(xiàn);

            WEAK:弱引用更積極地基于垃圾收集器狀態(tài)和弱引用規(guī)則移除對象;常見使用WeakReference來實(shí)現(xiàn);

            4.過期時間

            設(shè)置過期時間,讓緩存數(shù)據(jù)在指定時間過后自動刪除;常見的過期數(shù)據(jù)刪除策略有兩種方式:被動刪除和主動刪除;

            被動刪除:每次進(jìn)行g(shù)et/put操作的時候都會檢查一下當(dāng)前key是否已經(jīng)過期,如果過期則刪除,類似如下代碼:

            if (System.currentTimeMillis() - lastClear > clearInterval) {

            clear();

            }

            主動刪除:專門有一個job在后臺定期去檢查數(shù)據(jù)是否過期,如果過期則刪除,這其實(shí)可以有效的處理冷數(shù)據(jù);

            5.線程安全

            盡量用線程安全的類去存儲數(shù)據(jù),比如使用ConcurrentHashMap代替HashMap;或者提供相應(yīng)的同步處理類,比如Mybatis提供了SynchronizedCache:

            public synchronized void putObject(Object key, Object object) {

            ...省略...

            }

            @Override

            public synchronized Object getObject(Object key) {

            ...省略...

            }

            6.簡明的接口

            提供常用的get,put,remove,clear,getSize方法即可,比如Mybatis的Cache接口:

            public interface Cache {

            String getId();

            void putObject(Object key, Object value);

            Object getObject(Object key);

            Object removeObject(Object key);

            void clear();

            int getSize();

            ReadWriteLock getReadWriteLock();

            }

            再來看看guava提供的Cache接口,相對來說也是比較簡潔的:

            public interface Cache<K, V> {

            V getIfPresent(@CompatibleWith("K") Object key);

            V get(K key, Callable<? extends V> loader) throws ExecutionException;

            ImmutableMap<K, V> getAllPresent(Iterable<?> keys);

            void put(K key, V value);

            void putAll(Map<? extends K, ? extends V> m);

            void invalidate(@CompatibleWith("K") Object key);

            void invalidateAll(Iterable<?> keys);

            void invalidateAll();

            long size();

            CacheStats stats();

            ConcurrentMap<K, V> asMap();

            void cleanUp();

            }

            7.是否持久化

            持久化的好處是重啟之后可以再次加載文件中的數(shù)據(jù),這樣就起到類似熱加載的功效;比如ehcache提供了是否持久化磁盤緩存的功能,將緩存數(shù)據(jù)存放在一個.data文件中;

            diskPersistent="false" //是否持久化磁盤緩存

            redis更是將持久化功能發(fā)揮到極致,慢慢的有點(diǎn)像數(shù)據(jù)庫了;提供了AOF和RDB兩種持久化方式;當(dāng)然很多情況下可以配合使用兩種方式;

            8.阻塞機(jī)制

            除了在Mybatis中看到了BlockingCache來實(shí)現(xiàn)此功能,之前在看<<java并發(fā)編程實(shí)戰(zhàn)>>的時候其中有實(shí)現(xiàn)一個很完美的緩存,大致代碼如下:

            public class Memoizerl<A, V> implements Computable<A, V> {

            private final Map<A, Future<V>> cache = new ConcurrentHashMap<A, Future<V>>();

            private final Computable<A, V> c;

            public Memoizerl(Computable<A, V> c) {

            this.c = c;

            }

            @Override

            public V compute(A arg) throws InterruptedException, ExecutionException {

            while (true) {

            Future<V> f = cache.get(arg);

            if (f == null) {

            Callable<V> eval = new Callable<V>() {

            @Override

            public V call() throws Exception {

            return c.compute(arg);

            }

            };

            FutureTask<V> ft = new FutureTask<V>(eval);

            f = cache.putIfAbsent(arg, ft);

            if (f == null) {

            f = ft;

            ft.run();

            }

            try {

            return f.get();

            } catch (CancellationException e) {

            cache.remove(arg, f);

            }

            }

            }

            }

            }

            compute是一個計(jì)算很費(fèi)時的方法,所以這里把計(jì)算的結(jié)果緩存起來,但是有個問題就是如果兩個線程同時進(jìn)入此方法中怎么保證只計(jì)算一次,這里最核心的地方在于使用了ConcurrentHashMap的putIfAbsent方法,同時只會寫入一個FutureTask;

            總結(jié):要設(shè)計(jì)一個本地緩存都需要考慮哪些點(diǎn):數(shù)據(jù)結(jié)構(gòu),對象上限,清除策略,過期時間,線程安全,阻塞機(jī)制,實(shí)用的接口,是否持久化;當(dāng)然肯定有其他考慮點(diǎn),歡迎補(bǔ)充。

            tags:
            聲明:本站稿件版權(quán)均屬千鋒教育所有,未經(jīng)許可不得擅自轉(zhuǎn)載。
            10年以上業(yè)內(nèi)強(qiáng)師集結(jié),手把手帶你蛻變精英
            請您保持通訊暢通,專屬學(xué)習(xí)老師24小時內(nèi)將與您1V1溝通
            免費(fèi)領(lǐng)取
            今日已有369人領(lǐng)取成功
            劉同學(xué) 138****2860 剛剛成功領(lǐng)取
            王同學(xué) 131****2015 剛剛成功領(lǐng)取
            張同學(xué) 133****4652 剛剛成功領(lǐng)取
            李同學(xué) 135****8607 剛剛成功領(lǐng)取
            楊同學(xué) 132****5667 剛剛成功領(lǐng)取
            岳同學(xué) 134****6652 剛剛成功領(lǐng)取
            梁同學(xué) 157****2950 剛剛成功領(lǐng)取
            劉同學(xué) 189****1015 剛剛成功領(lǐng)取
            張同學(xué) 155****4678 剛剛成功領(lǐng)取
            鄒同學(xué) 139****2907 剛剛成功領(lǐng)取
            董同學(xué) 138****2867 剛剛成功領(lǐng)取
            周同學(xué) 136****3602 剛剛成功領(lǐng)取
            相關(guān)推薦HOT
            為什么說PHP與Swoole是優(yōu)異組合?

            PHP與Swoole在Web開發(fā)和網(wǎng)絡(luò)編程領(lǐng)域中,共同構(gòu)成了一種強(qiáng)大的解決方案。什么是PHPPHP是一種廣泛使用的開源服務(wù)器端腳本語言,特別適用于Web開...詳情>>

            2023-10-14 05:08:41
            Javaweb開發(fā)為什么需要分前后端?

            Javaweb開發(fā)采用前后端分離的設(shè)計(jì)模式是有著諸多理由的,以下分析了這種設(shè)計(jì)模式的主要特點(diǎn)和優(yōu)勢。什么是前后端分離在Web開發(fā)中,前后端分離是...詳情>>

            2023-10-14 05:05:24
            瀑布開發(fā)和敏捷開發(fā)的區(qū)別是什么?

            一、開發(fā)流程不同瀑布開發(fā)采用線性的開發(fā)流程,按照預(yù)先規(guī)劃的順序依次進(jìn)行需求分析、設(shè)計(jì)、編碼、測試和維護(hù)等環(huán)節(jié)。每個環(huán)節(jié)都有明確的交付物...詳情>>

            2023-10-14 04:47:33
            有哪款比較好用的免費(fèi)的缺陷管理工具?

            一、BugzillaBugzilla是一款廣泛使用的免費(fèi)缺陷管理工具,具備完善的缺陷管理功能,并支持多用戶協(xié)同工作。Bugzilla提供了強(qiáng)大的搜索和過濾功能...詳情>>

            2023-10-14 04:40:43
            USB Type C電纜正反插都可以?

            USB Type C電纜正反插都可以USB Type C電纜是一種通用連接標(biāo)準(zhǔn),其最顯著的特點(diǎn)是具備正反插功能。不論插頭的方向如何,用戶都可以輕松插入U(xiǎn)SB ...詳情>>

            2023-10-14 04:31:18