您好,登錄后才能下訂單哦!
今天就跟大家聊聊有關Java中如何高速Map存取,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。
高速Map存取
使用EnumMap來存取Key是Enum的,會有較快的速度,如下是一個網(wǎng)關返回對象Result的的狀態(tài)屬性,是一個枚舉類
public static enum Status { SUCCESS(1,"成功"),FAIL(2,"處理失敗"),DEGRADE(98,"成功降級"),UNKOWN(99,"未知異常"); private int code; String msg; Status(int code,String msg){ this.code = code; this.msg = msg; } public int getCode() { return code; } public String getMsg() { return msg; } }
考慮到定義微服務網(wǎng)關返回對象,應該盡量使用java自帶類型,以避免各種序列化,反序列化問題,網(wǎng)關不返回此枚舉值,而是返回msg字段,因此可以構(gòu)造一個EnumMap,Key為Status枚舉類型,Value為Status.msg 屬性
Map<Status,String> enumMap =null; private void initEnumMap(){ enumMap = new EnumMap<Status,String>(Status.class); for(Status status:Status.values()) { enumMap.put(status,status.msg); } }
構(gòu)造EnumMap的時候,內(nèi)部實際上通過一個數(shù)組保存了所有的枚舉值,索引是枚舉的ordinal得到 當要根據(jù)Enum來操作EnumMap,只需要先調(diào)用ordinal,得到其索引,然后直接操作數(shù)組即可。操作一維數(shù)組有這最快的速度
有些場景下Key是int類型,這時候可以參考第二章的IntMap
有很多Key-Value使用場景,都可以轉(zhuǎn)化為根據(jù)索引對數(shù)組的存取,我們學過的C語言,操作的是變量名,但實際上還是根據(jù)指針獲取到內(nèi)存中的值,Beetl模板語言,對變量的訪問,也不像其他腳本語言那樣,通過變量名訪問Map獲取其值,而是在編譯期間就為這個變量分配好了索引值,所有變量都保存在一個一維數(shù)組里,這樣的存取,相比于Map存取,有十倍以上性能提高。
如下一段腳本語言
var a = 1; var b = 2+a;
有些語言引擎會翻譯成類似如下java代碼
context.put("a",1); context.put("b",context.get("a")+2);
這里context是一個Map。從Map里通過Key存取盡管很快,但是Beetl還是在解析腳本語言的時候給變量設置了數(shù)組所在索引,因此如上腳本在Beetl中翻譯如下
Object[] vars = context.vars; vars[0] =1 ; vars[1] = vars[0]+2
這里為變量a,b 分別設置了在變量表中的索引是0和1;
曾優(yōu)化過一個電商的基礎組件,電商系統(tǒng)每天調(diào)用這個組件的次數(shù)高達10+萬億次,這個組件是用來統(tǒng)計方法調(diào)用的時長,收集一段時間后,定期發(fā)送到 分析系統(tǒng),用于查找和分析方法的性能,其中有一部分代碼是記錄以調(diào)用時長分類,記錄條用次數(shù),下面的代碼
Watch watch = Watch.instance("orderByWx"); //初始化,從微信來的訂單 //調(diào)用其他業(yè)務邏輯..... Profile.add(watch.endWatch());//記錄一次
Watch類定義如下
public class Watch { String key; long start; long millis =-1; private Watch(String key){ this.key = key; this.start = System.nanoTime(); } public static Watch instance(String key){ return new Watch(key); } public Watch endWatch(){ millis = millisConsume(); return this; } /** * 返回方法調(diào)用消耗的毫秒 * [@return](https://my.oschina.net/u/556800) */ private long millisConsume(){ return TimeUnit.NANOSECONDS.toMillis(System.nanoTime()-start); } }
Watch的key屬性記錄調(diào)用類型,如訂單調(diào)用,商品查詢信息等,可以為任意值,start屬性記錄了調(diào)用時候的時間點,millis會在調(diào)用endWatch后記錄調(diào)用消耗的毫秒數(shù)。
Profile類用來記錄監(jiān)控信息,并通過其他后臺線程發(fā)送到性能分析中心,例子做了一定簡化,只呈現(xiàn)保存部分
public class Profile { //調(diào)用時長和調(diào)用次數(shù) static Map<Integer, AtomicInteger> countMap = new ConcurrentHashMap<>(); /** * 對調(diào)用時間計數(shù) * [@param](https://my.oschina.net/u/2303379) watch */ public static void addWatch(Watch watch){ int consumeTime = (int)watch.millis; AtomicInteger count = countMap.get(consumeTime); if(count==null){ count = new AtomicInteger(); AtomicInteger old = countMap.putIfAbsent(consumeTime,count); if(old!=null){ count = old; } } count.incrementAndGet(); } }
Profile會初始化一個ConcurrentHashMap用于計數(shù),Key為Integer類型,表示調(diào)用時長,Value為AtomicInteger,用來計數(shù),每次調(diào)用,都會自增一個
Profile性能有一點優(yōu)化空間,如果從業(yè)務角度考慮,大部分需要監(jiān)控的方法或者代碼塊,執(zhí)行時間并不長,假設不超過32毫秒(這是一個假設值,根據(jù)系統(tǒng)運維統(tǒng)計分析后得出),因此,可以考慮用一個32長度的數(shù)組來存放32毫秒以內(nèi)的所有計數(shù),超過32毫秒的再沿用以前的方法
static Map<Integer, AtomicInteger> countMap = new ConcurrentHashMap<>(); static final int MAX = 32; //保存消耗時間為32毫秒的調(diào)用次數(shù) static AtomicInteger[] counts = new AtomicInteger[MAX]; static{ for(int i=0;i<MAX;i++){ counts[i] = new AtomicInteger(); } } /** * 對調(diào)用時間計數(shù) * [@param](https://my.oschina.net/u/2303379) watch */ public static void addWatch(Watch watch){ int consumeTime = (int)watch.millis; if(consumeTime<MAX){ counts[consumeTime].incrementAndGet(); return ; } AtomicInteger count = countMap.get(consumeTime); //原有的Profile.addWatch邏輯,在此忽略 }
新完善的代碼使用counts數(shù)組記錄32毫秒以內(nèi)調(diào)用計數(shù),因此當addWatch被調(diào)用的時候,先判斷millis是否小于32毫秒,如果是,直接用數(shù)組獲取計數(shù)器,然后自增。否則,沿用以前的邏輯
優(yōu)化后,通過JMH測試(com.ibeetl.code.ch05.WatchTest),性能略有提升,如下輸出:
Benchmark Mode Samples Score Score error Units c.i.c.c.WatchTest.better thrpt 20 16447.171 2195.344 ops/ms c.i.c.c.WatchTest.general thrpt 20 11566.545 601.579 ops/ms
性能優(yōu)化提高了40%,盡管看著不如本書其他例子性能提升那么明顯,但考慮這是一個基礎工具,性能提升會對所有系統(tǒng)都有幫助,實際上,作者優(yōu)化為跟此性能監(jiān)控工具后,對業(yè)務系統(tǒng)的有提升5%的性能提升,在擁有數(shù)十萬臺服務器的大型電商系統(tǒng),這個系統(tǒng)提升還是有意義的。
看完上述內(nèi)容,你們對Java中如何高速Map存取有進一步的了解嗎?如果還想了解更多知識或者相關內(nèi)容,請關注億速云行業(yè)資訊頻道,感謝大家的支持。
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。