国产精品电影_久久视频免费_欧美日韩国产激情_成年人视频免费在线播放_日本久久亚洲电影_久久都是精品_66av99_九色精品美女在线_蜜臀a∨国产成人精品_冲田杏梨av在线_欧美精品在线一区二区三区_麻豆mv在线看

Java 中的五個代碼性能提升技巧,最高提升近10倍

開發 后端
這篇文章介紹幾個 Java 開發中可以進行性能優化的小技巧,希望大家喜歡。

[[442793]]

 這篇文章介紹幾個 Java 開發中可以進行性能優化的小技巧,雖然大多數情況下極致優化代碼是沒有必要的,但是作為一名技術開發者,我們還是想追求代碼的更小、更快,更強。如果哪天你發現程序的運行速度不盡人意,可能會想到這篇文章。

提示:我們不應該為了優化而優化,這有時會增加代碼的復雜度。

這篇文章中的代碼都在以下環境中進行性能測試。

  •  JMH version: 1.33(Java 基準測試框架)
  •  VM version: JDK 17, OpenJDK 64-Bit Server VM, 17+35-2724

通過這篇文章的測試,將發現以下幾個操作的性能差異。

  1.   預先分配 HashMap 的大小,提高 1/4 的性能。
  2.   優化 HashMap 的 key,性能相差 9.5 倍。
  3.   不使用  Enum.values() 遍歷,Spring 也曾如此優化。
  4.   使用 Enum 代替 String 常量,性能高出 1.5 倍。
  5.   使用高版本 JDK,基礎操作有 2-5 倍性能差異。

預先分配 HashMap 的大小

HashMap 是 Java 中最為常用的集合之一,大多數的操作速度都非常快,但是 HashMap 在調整自身的容量大小時是很慢且難以自動優化,因此我們在定義一個 HashMap 之前,應該盡可能的給出它的容量大小。給出 size 值時要考慮負載因子,HashMap 默認負載因子是 0.75,也就是要設置的 size 值要除于 0.75。

相關文章:HashMap 源碼分析解讀

下面使用 JMH 進行基準測試,測試分別向初始容量為 16 和 32 的 HashMap 中插入 14 個元素的效率。 

  1. /**  
  2.  * @author https://www.wdbyte.com  
  3.  */  
  4. @State(Scope.Benchmark)  
  5. @Warmup(iterations = 3,time = 3 
  6. @Measurement(iterations = 5,time = 3 
  7. public class HashMapSize {  
  8.     @Param({"14"})  
  9.     int keys;  
  10.     @Param({"16", "32"})  
  11.     int size;  
  12.     @Benchmark  
  13.     public HashMap<Integer, Integer> getHashMap() {  
  14.         HashMap<Integer, Integer> map = new HashMap<>(size); 
  15.          for (int i = 0; i < keys; i++) {  
  16.             map.put(i, i);  
  17.         }  
  18.         return map; 
  19.    }  

HashMap 的初始容量是 16,負責因子 0.75,即最多插入 12 個元素,再插入時就要進行擴容,所以插入 14 個元素過程中需要擴容一次,但是如果 HashMap 初始化時就給了 32 容量,那么最多可以承載 32 * 0.75 = 24 個元素,所以插入 14 個元素時是不需要擴容操作的。 

  1. # JMH version: 1.33  
  2. # VM version: JDK 17, OpenJDK 64-Bit Server VM, 17+35-2724  
  3. Benchmark               (keys)  (size)   Mode  Cnt        Score        Error  Units  
  4. HashMapSize.getHashMap      14      16  thrpt   25  4825825.152 ± 323910.557  ops/s  
  5. HashMapSize.getHashMap      14      32  thrpt   25  6556184.664 ± 711657.679  ops/s 

可以看到在這次測試中,初始容量為32 的 HashMap 比初始容量為 16 的 HashMap 每秒可以多操作 26% 次,已經有 1/4 的性能差異了。

 優化 HashMap 的 key

如果 HashMap 的 key 值需要用到多個 String 字符串時,把字符串作為某個類屬性,然后使用這個類的實例作為 key 會比使用字符串拼接效率更高。

下面測試使用兩個字符串拼接作為 key,和把兩個字符串作為 MutablePair 類的屬性引用,然后使用 MutablePair 對象作為 key 的運行效率差異。 

  1. /**  
  2.  * @author https://www.wdbyte.com  
  3.  */  
  4. @State(Scope.Benchmark)  
  5. @Warmup(iterations = 3time = 3 
  6. @Measurement(iterations = 5time = 3 
  7. public class HashMapKey {  
  8.     private int size = 1024 
  9.     private Map<String, Object> stringMap;  
  10.     private Map<Pair, Object> pairMap;  
  11.     private String[] prefixes;  
  12.     private String[] suffixes;  
  13.     @Setup(Level.Trial)  
  14.     public void setup() {  
  15.         prefixes = new String[size];  
  16.         suffixes = new String[size];  
  17.         stringMap = new HashMap<>();  
  18.         pairMap = new HashMap<>();  
  19.         for (int i = 0; i < size; ++i) {  
  20.             prefixes[i] = UUID.randomUUID().toString();  
  21.             suffixes[i] = UUID.randomUUID().toString();  
  22.             stringMap.put(prefixes[i] + ";" + suffixes[i], i);  
  23.             // use new String to avoid reference equality speeding up the equals calls  
  24.             pairMap.put(new MutablePair(prefixes[i], suffixes[i]), i);  
  25.         }  
  26.     }  
  27.     @Benchmark  
  28.     @OperationsPerInvocation(1024)  
  29.     public void stringKey(Blackhole bh) {  
  30.         for (int i = 0; i < prefixes.length; i++) {  
  31.             bh.consume(stringMap.get(prefixes[i] + ";" + suffixes[i]));  
  32.         }  
  33.     }  
  34.     @Benchmark  
  35.     @OperationsPerInvocation(1024)  
  36.     public void pairMap(Blackhole bh) {  
  37.         for (int i = 0; i < prefixes.length; i++) {  
  38.             bh.consume(pairMap.get(new MutablePair(prefixes[i], suffixes[i])));  
  39.         }  
  40.     }  

測試結果: 

  1. # JMH version: 1.33  
  2. # VM version: JDK 17, OpenJDK 64-Bit Server VM, 17+35-2724  
  3. Benchmark              Mode  Cnt         Score         Error  Units  
  4. HashMapKey.pairMap    thrpt   25  89295035.436 ± 6498403.173  ops/s  
  5. HashMapKey.stringKey  thrpt   25   9410641.728 ±  389850.653  ops/s 

可以發現使用對象引用作為 key 的性能,是使用 String 拼接作為 key 的性能的 9.5 倍。 

不使用  Enum.values() 遍歷

我們通常會使用  Enum.values() 進行枚舉類遍歷,但是這樣每次調用都會分配枚舉類值數量大小的數組用于操作,這里完全可以緩存起來,以減少每次內存分配的時間和空間消耗。 

  1. /**  
  2.  * 枚舉類遍歷測試  
  3.  *  
  4.  * @author https://www.wdbyte.com  
  5.  */  
  6. @State(Scope.Benchmark)  
  7. @Warmup(iterations = 3time = 3 
  8. @Measurement(iterations = 5time = 3 
  9. @BenchmarkMode(Mode.AverageTime)  
  10. @OutputTimeUnit(TimeUnit.MILLISECONDS)  
  11. public class EnumIteration {  
  12.     enum FourteenEnum {  
  13.         a,b,c,d,e,f,g,h,i,j,k,l,m,n;  
  14.         static final FourteenEnum[] VALUES;  
  15.         static {  
  16.             VALUES = values();  
  17.         }  
  18.     }  
  19.     @Benchmark  
  20.     public void valuesEnum(Blackhole bh) {  
  21.         for (FourteenEnum value : FourteenEnum.values()) {  
  22.             bh.consume(value.ordinal());  
  23.         }  
  24.     }  
  25.     @Benchmark  
  26.     public void enumSetEnum(Blackhole bh) { 
  27.         for (FourteenEnum value : EnumSet.allOf(FourteenEnum.class)) {  
  28.             bh.consume(value.ordinal());  
  29.         }  
  30.     }  
  31.     @Benchmark  
  32.     public void cacheEnums(Blackhole bh) {  
  33.         for (FourteenEnum value : FourteenEnum.VALUES) {  
  34.             bh.consume(value.ordinal());  
  35.         }  
  36.     }  

運行結果 

  1. # JMH version: 1.33  
  2. # VM version: JDK 17, OpenJDK 64-Bit Server VM, 17+35-2724  
  3. Benchmark                   Mode  Cnt         Score         Error  Units  
  4. EnumIteration.cacheEnums   thrpt   25  15623401.567 ± 2274962.772  ops/s  
  5. EnumIteration.enumSetEnum  thrpt   25   8597188.662 ±  610632.249  ops/s  
  6. EnumIteration.valuesEnum   thrpt   25  14713941.570 ±  728955.826  ops/s 

很明顯使用緩存后的遍歷速度是最快的,使用 EnumSet 遍歷效率是最低的,這很好理解,數組的遍歷效率是大于哈希表的。

可能你會覺得這里使用 values() 緩存和直接使用 Enum.values() 的效率差異很小,其實在某些調用頻率很高的場景下是有很大區別的,在 Spring 框架中,曾使用 Enum.values() 這種方式在每次響應時遍歷 HTTP 狀態碼枚舉類,這在請求量大時造成了不必要的性能開銷,后來進行了 values() 緩存優化。

下面是這次提交的截圖:

Spring Enum.values 改動 

使用 Enum 代替 String 常量

使用 Enum 枚舉類代替 String 常量有明顯的好處,枚舉類強制驗證,不會出錯,同時使用枚舉類的效率也更高。即使作為 Map 的 key 值來看,雖然 HashMap 的速度已經很快了,但是使用 EnumMap 的速度可以更快。

提示:不要為了優化而優化,這會增加代碼的復雜度。

下面測試使用使用 Enum 作為 key,和使用 String 作為 key,在 map.get 操作下的性能差異。 

  1. /**  
  2.  * @author https://www.wdbyte.com  
  3.  */  
  4. @State(Scope.Benchmark)  
  5. @Warmup(iterations = 3time = 3 
  6. @Measurement(iterations = 5time = 3 
  7. public class EnumMapBenchmark {  
  8.     enum AnEnum {  
  9.         a, b, c, d, e, f, g,  
  10.         h, i, j, k, l, m, n,  
  11.         o, p, q,    r, s, t,  
  12.         u, v, w,    x, y, z;  
  13.     }  
  14.     /** 要查找的 key 的數量 */  
  15.     private static int size = 10000 
  16.     /** 隨機數種子 */  
  17.     private static int seed = 99 
  18.     @State(Scope.Benchmark)  
  19.     public static class EnumMapState {  
  20.         private EnumMap<AnEnum, String> map;  
  21.         private AnEnum[] values;  
  22.         @Setup(Level.Trial)  
  23.         public void setup() {  
  24.             map = new EnumMap<>(AnEnum.class);  
  25.             values = new AnEnum[size];  
  26.             AnEnum[] enumValues = AnEnum.values();  
  27.             SplittableRandom random = new SplittableRandom(seed);  
  28.             for (int i = 0; i < size; i++) {  
  29.                 int nextInt = random.nextInt(0, Integer.MAX_VALUE);  
  30.                 values[i] = enumValues[nextInt % enumValues.length];  
  31.             }  
  32.             for (AnEnum value : enumValues) {  
  33.                 map.put(value, UUID.randomUUID().toString());  
  34.             }  
  35.         }  
  36.     }  
  37.     @State(Scope.Benchmark)  
  38.     public static class HashMapState{  
  39.         private HashMap<String, String> map;  
  40.         private String[] values;  
  41.         @Setup(Level.Trial)  
  42.         public void setup() {  
  43.             map = new HashMap<>();  
  44.             values = new String[size];  
  45.             AnEnum[] enumValues = AnEnum.values();  
  46.             int pos = 0 
  47.             SplittableRandom random = new SplittableRandom(seed);  
  48.             for (int i = 0; i < size; i++) {  
  49.                 int nextInt = random.nextInt(0, Integer.MAX_VALUE);  
  50.                 values[i] = enumValues[nextInt % enumValues.length].toString();  
  51.             }  
  52.             for (AnEnum value : enumValues) {  
  53.                 map.put(value.toString(), UUID.randomUUID().toString());  
  54.             }  
  55.         }  
  56.     }  
  57.     @Benchmark  
  58.     public void enumMap(EnumMapState state, Blackhole bh) {  
  59.         for (AnEnum value : state.values) {  
  60.             bh.consume(state.map.get(value));  
  61.         }  
  62.     }  
  63.     @Benchmark  
  64.     public void hashMap(HashMapState state, Blackhole bh) {  
  65.         for (String value : state.values) {  
  66.             bh.consume(state.map.get(value));  
  67.         }  
  68.     }  

運行結果: 

  1. # JMH version: 1.33  
  2. # VM version: JDK 17, OpenJDK 64-Bit Server VM, 17+35-2724  
  3. Benchmark                  Mode  Cnt      Score      Error  Units  
  4. EnumMapBenchmark.enumMap  thrpt   25  22159.232 ± 1268.800  ops/s  
  5. EnumMapBenchmark.hashMap  thrpt   25  14528.555 ± 1323.610  ops/s 

很明顯,使用 Enum 作為 key 的性能比使用 String 作為 key 的性能高出 1.5 倍。但是仍然要根據實際情況考慮是否使用 EnumMap 和 EnumSet。

 使用高版本 JDK

String 類應該是 Java 中使用頻率最高的類了,但是 Java 8 中的  String 實現相比高版本 JDK ,則占用空間更多,性能更低。

下面測試 String 轉 bytes 和 bytes 轉 String 在 Java 8 以及 Java 11 中的性能開銷。 

  1. /**  
  2.  * @author https://www.wdbyte.com  
  3.  * @date 2021/12/23  
  4.  */  
  5. @State(Scope.Benchmark)  
  6. @Warmup(iterations = 3time = 3 
  7. @Measurement(iterations = 5time = 3 
  8. public class StringInJdk {  
  9.     @Param({"10000"})  
  10.     private int size;  
  11.     private String[] stringArray;  
  12.     private List<byte[]> byteList;  
  13.     @Setup(Level.Trial)  
  14.     public void setup() {  
  15.         byteList = new ArrayList<>(size);  
  16.         stringArray = new String[size]; 
  17.         for (int i = 0; i < size; i++) {  
  18.             String uuid = UUID.randomUUID().toString();  
  19.             stringArray[i] = uuid;  
  20.             byteList.add(uuid.getBytes(StandardCharsets.UTF_8));  
  21.         }  
  22.     }  
  23.     @Benchmark  
  24.     public void byteToString(Blackhole bh) {  
  25.         for (byte[] bytes : byteList) {  
  26.             bh.consume(new String(bytes, StandardCharsets.UTF_8));  
  27.         }  
  28.     }  
  29.     @Benchmark 
  30.  
  31.     public void stringToByte(Blackhole bh) {  
  32.         for (String s : stringArray) {  
  33.             bh.consume(s.getBytes(StandardCharsets.UTF_8));  
  34.         }  
  35.     }  

測試結果: 

  1. # JMH version: 1.33  
  2. # VM version: JDK 1.8.0_151, Java HotSpot(TM) 64-Bit Server VM, 25.151-b12  
  3. Benchmark                 (size)   Mode  Cnt     Score     Error  Units  
  4. StringInJdk.byteToString   10000  thrpt   25  2396.713 ± 133.500  ops/s  
  5. StringInJdk.stringToByte   10000  thrpt   25  1745.060 ±  16.945  ops/s  
  6. # JMH version: 1.33  
  7. # VM version: JDK 17, OpenJDK 64-Bit Server VM, 17+35-2724  
  8. Benchmark                 (size)   Mode  Cnt     Score     Error  Units  
  9. StringInJdk.byteToString   10000  thrpt   25  5711.954 ±  41.865  ops/s  
  10. StringInJdk.stringToByte   10000  thrpt   25  8595.895 ± 704.004  ops/s 

可以看到在 bytes 轉 String 操作上,Java 17 的性能是 Java 8 的 2.5 倍左右,而 String 轉 bytes 操作,Java 17 的性能是 Java 8 的 5 倍。關于字符串的操作非常基礎,隨處可見,可見高版本的優勢十分明顯。 

 

責任編輯:龐桂玉 來源: Hollis
相關推薦

2019-09-26 08:33:51

Nginx技術Java

2020-07-25 20:01:45

CSS前端

2020-03-26 12:38:15

代碼節點數據

2024-11-18 19:00:29

2011-07-01 10:11:39

2021-12-28 14:10:41

開發技能代碼

2020-07-22 08:30:02

代碼開發工具

2014-03-26 10:00:06

RailsRails性能

2018-08-23 17:45:52

2017-10-30 15:22:29

代碼可讀性技巧

2024-08-06 12:35:42

C#代碼重構

2017-11-06 14:33:54

Web開發服務器網絡

2024-10-29 08:21:05

2020-07-21 15:40:55

NginxJava服務器

2025-05-27 01:55:00

TypeScript開發者項目

2021-05-11 12:30:21

PyTorch代碼Python

2024-11-01 07:30:00

2024-06-11 00:09:00

JavaScript模式變量

2024-11-14 11:29:38

點贊
收藏

51CTO技術棧公眾號

亚洲视频一二| 日韩美女一区二区三区| 久久久亚洲欧洲日产国码αv| 国产精品久久久久久久久久直播 | 日韩69视频在线观看| 成人高潮a毛片免费观看网站| 亚洲三级 欧美三级| 日韩大尺度黄色| 中文字幕久热精品在线视频| 久久sese| 免费97视频在线精品国自产拍| 日韩黄色三级在线观看| 色999日韩欧美国产| 欧洲美女精品免费观看视频 | 亚洲一区二区三区毛片| 日韩啪啪电影网| 国产精品成人一区| 欧美二区不卡| 亚洲成年人在线播放| xxx性欧美| 亚洲男人av电影| 日韩国产大片| 欧美精品18videos性欧| 午夜先锋成人动漫在线| 国产精品欧美一区二区三区奶水| 欧美成人69av| 亚洲成人第一| 久久综合999| 黄色av免费| 欧美性猛交丰臀xxxxx网站| 免费在线看a| 亚洲欧美国内爽妇网| 免费看一区二区三区| 国产成人精品一区二区| 国产精品v亚洲精品v日韩精品 | av免费观看国产| 国产精品视频免费看| 有码av在线| 日韩欧美国产1| 久久精品国产福利| 日韩美女免费视频| 裸体一区二区| 免费超爽大片黄| 亚洲制服丝袜av| 1stkiss在线漫画| 日韩三级影视基地| 999视频精品| 亚洲a∨一区二区三区| 久久久久久久久久久久久女国产乱| 99re6热在线精品视频播放| 欧美一级在线观看| 99热在线网站| 欧美精品日韩一本| 精品美女一区| 成人av色在线观看| 精品在线一区二区三区| 91在线直播亚洲| 国产一区二区三区免费在线观看| 奇米影音第四色| 欧美日韩不卡在线| 亚洲综合色婷婷在线观看| 亚洲国产精彩中文乱码av在线播放| av免费在线一区| 国产精品视频不卡| 激情综合色播五月| 交换国产精品视频一区| 日韩av在线免费| 尤物yw193can在线观看| 久久精品99久久久久久久久 | 老司机一区二区| 男女羞羞电影免费观看| 亚洲大胆人体在线| 九九热精品视频在线观看| 日本黄色播放器| 欧美午夜女人视频在线| 国产成年精品| 视频在线精品一区| 亚洲国产精品一区二区尤物区| 日本精品裸体写真集在线观看| 亚洲精品欧美日韩| 日本一区二区成人| 9999精品成人免费毛片在线看 | 婷婷六月天在线| 精品电影一区二区三区| 国产大片一区| 黄色一级大片在线观看| 亚洲国产精品成人va在线观看| 久久国产亚洲精品| mm1313亚洲国产精品无码试看| 亚洲国产精品热久久| 欧美1区2区| av最新网址| 日韩有码在线电影| 日本一不卡视频| 国产日产精品久久久久久婷婷| 欧美黑人巨大精品一区二区| 久久99国内精品| 中文字幕在线免费| 欧美精品丝袜久久久中文字幕| 国产呦萝稀缺另类资源| 日本成人免费在线| 国产激情精品久久久第一区二区 | av一本在线| 欧美激情精品久久久久久免费印度| 日韩黄色免费电影| 91社区在线观看播放| 国产精品入口日韩视频大尺度| xnxx国产精品| 曰本一区二区| 精品视频在线观看一区二区| 亚洲高清久久久久久| 99伊人成综合| 国产在线一在线二| 成人欧美在线观看| 一级精品视频在线观看宜春院| 国产精东传媒成人av电影| www.好吊操| 国产亚洲精品一区二555| 精品一区二区在线看| 日韩少妇视频| 日韩欧美电影一区二区| 91精品国产综合久久香蕉麻豆| 精品电影一区| 在线观看a视频| 国产亚洲精品自在久久| 欧美午夜电影网| 亚洲国产高清一区| 麻豆传媒视频在线| 欧美日韩精品免费观看| 日韩欧美在线网站| 蜜臀av一区二区在线观看| 国产精品高颜值在线观看| 第九区2中文字幕| 一区二区三区精品99久久| 不卡的av网站| 亚洲码欧美码一区二区三区| 亚洲一区在线不卡| 青青a在线精品免费观看| 一区二区三区在线免费视频| 日本一区二区免费高清| 视频一区二区在线播放| 91九色最新地址| 欧美fxxxxxx另类| 成人在线免费公开观看视频| 久久精品日产第一区二区三区| 欧美午夜寂寞影院| 老司机免费视频一区二区三区| 高清av不卡| 成年人网站大全| 日本成人激情视频| 欧美午夜女人视频在线| 香蕉亚洲视频| 香蕉成人影院| 肥女人的一级毛片| 懂色一区二区三区av片| 亚洲国产成人爱av在线播放| 成人毛片老司机大片| 青草久久视频| 国产露出视频在线观看| 狠狠色伊人亚洲综合网站色 | 国产成人一区二区三区影院| 亚洲校园激情春色| 国产人妖一区| 春色成人在线视频| 成人xxxx视频| 成人免费看黄网址| 成人嫩草影院免费观看| 8x8ⅹ国产精品一区二区二区| 国产精品入口免费| 亚洲综合视频一区| 日韩精品一区二区三区四| 一区二区在线中文字幕电影视频 | 日韩av电影免费观看| 色噜噜一区二区| h无码动漫在线观看| 国产91在线视频观看| 男女激情片在线观看| 五月天婷婷在线视频| 青草综合视频| 亚洲麻豆一区| 国产女主播视频一区二区| 精品久久久久久久久久久久久久| 欧美制服丝袜第一页| 一区二区欧美久久| 国产99在线|中文| 国产精品区一区二区三含羞草| 日本一级淫片演员| caoporen人人| 黄网av在线| 欧美.日韩.国产.一区.二区| 日韩不卡免费视频| 一区二区三区精品视频| 亚洲精品视频在线播放| 国产成人精品a视频一区www| 一级毛片高清视频| 成人爽a毛片免费啪啪动漫| 色呦呦在线看| 亚洲一区二区免费在线观看| 亚洲一区区二区| 欧美激情在线观看|