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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

开发高性能JAVA应用程序基础(集合篇)

發(fā)布時間:2023/12/18 编程问答 25 如意码农
生活随笔 收集整理的這篇文章主要介紹了 开发高性能JAVA应用程序基础(集合篇) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

集合類在開發(fā)中使用非常頻繁,使用時合理的選擇對提高性能小有幫助。而且大部分面試都會有與集合相關(guān)的問題,例如ArrayList和LinkedList的對比。

了解API的集成與操作架構(gòu),才能了解何時該采用哪個類,而不會只能抄寫范例。本文也嘗試用一些現(xiàn)實生活中的物品來描述各個集合類的特性,僅僅是幫助快速理解和記憶,不必太過較真。

首先看類結(jié)構(gòu)圖:

按用途分為可重復收集對象的List、不可重復的Set和鍵值對應的Map三個頂層接口,對應三個最常用的實現(xiàn)類是ArrayList、HashSet和HashMap,如果沒有其他的限制它們應該是默認的選擇。

注意Vector、Hashtable和Stack上都有Legacy字樣,如果不是為了兼容舊代碼,不應再使用這三個類。

一、ArrayList對比LinkedList

很多文章介紹時直接說ArrayList查詢快插入慢,LinkedList插入刪除快,但是這個是有前提的。

代碼為證:

  1. public static void main(String[] args) {
  2. List<Integer> array1 = new ArrayList<>(), array2 = new ArrayList<>();
  3. List<Integer> link1 = new LinkedList<>(), link2 = new LinkedList<>();
  4. for(int i = 0; i < 100000; i++) {
  5. array1.add(i); array2.add(i);
  6. link1.add(i); link2.add(i);
  7. }
  8. System.out.println("從0開始ArrayList消耗:" + getTime(array1, 0));
  9. System.out.println("從0開始LinkedList消耗:" + getTime(link1, 0));
  10. System.out.println("從50000開始ArrayList消耗:" + getTime(array2, 50000));
  11. System.out.println("從50000開始LinkedList消耗:" + getTime(link2, 50000));
  12. }
  13. public static long getTime(List<Integer> list, int index){
  14. long start = System.nanoTime();
  15. for(int i = 0; i< 100000; i++){
  16. list.add(index, i);
  17. }
  18. return TimeUnit.MILLISECONDS.convert(System.nanoTime() - start, TimeUnit.NANOSECONDS);
  19. }
  1. 從0開始ArrayList消耗:3701
  2. 從0開始LinkedList消耗:17
  3. 從50000開始ArrayList消耗:2370
  4. 從50000開始LinkedList消耗:13363

來分析:

ArrayList內(nèi)部使用Object數(shù)組來保存收集的對象,數(shù)組在內(nèi)存中是連續(xù)的線性空間。可以想象成一排緊緊排列的桌子,因為緊密連接距離較短,隨機找到某個位置(索引)的桌子會比較快,但是如果想在中間某個位置插入一個新的桌子,那必須把排在后面的桌子一張一張向后移動,以空出一個位置。同樣,如果刪除一個桌子(怪異的說法),則需要把后面一張一張向前移動。如果是更換呢,很簡單,搬走一張桌子,把新的放在原來的位置(快)。

LinkedList內(nèi)部是雙向鏈表結(jié)構(gòu),形象是一個用線串聯(lián)的珠串,兩個珠子之間的線可能非常長。如果想找到某一個位置的珠子,必須從頭開始,沿著線一個接一個的向后找(查詢慢)。如果想在兩個珠子之間插入一個新的,那就很簡單了,把中間的線拆開,新珠子兩端的線分別接上。刪除同樣簡單。

那么為什么測試結(jié)果中LinkedList第二次表現(xiàn)遠遠落后呢?原因是想插入首先必須先定位到位置,第二次測試選定從索引50000開始,LinkedList每次操作前都需要從0開始尋址到50000,查詢消耗大量時間,所以實際執(zhí)行很慢。

LinkedList可以當作Stack和Queue使用,這是ArrayList不具備的。

二、HashMap和TreeMap

HashMap內(nèi)部使用一個名為Entry的內(nèi)部類數(shù)組保存key-value對,使用無參構(gòu)造方法的情況下, 創(chuàng)建一個長度為16(capacity)的數(shù)組。其中的16個存儲位置通常稱為哈希桶。當存儲一個Entry對象時,首先通過key的hashCode()獲得一個整形的散列碼,和數(shù)組長度做取模計算獲得位置索引。

那么一個明顯的問題是,如果兩個key經(jīng)過上面的計算后得到一個相同的位置索引怎么辦?這種情況稱為哈希沖突,HashMap解決的辦法是把新Entry和原來位置的Entry建立起鏈表,如果再有第三個相同index的key加進來,那么繼續(xù)加在鏈表的前部。一個幫助記憶的形象是皇帝冠冕前的多列垂珠。

調(diào)用get(key)方法查找時,先通過hashCode()和取模計算獲得第幾個桶,再對桶上的鏈表遍歷列表并通過key.equals()逐個比較來確定對象。

這樣看來如果鏈表過長,也會影響查詢速度,這時候就是負載因子(load factor)出場的時候了。當HashMap中已存入的對象數(shù)量超過capacity * load factor時,會對數(shù)組擴容,變?yōu)樵瓉淼膬杀丁?/p>

一些優(yōu)化提示:

1 如果開發(fā)時已經(jīng)預知HashMap要存入的對象數(shù)量,可以直接指定初始容量,避免頻繁擴容

2 int和String非常適合當作key

3 如果key使用自己的對象,那么一個好的hashCode()算法非常重要,應該使對象盡可能均勻的分布在各哈希桶,同時應該覆蓋equals方法。Effective Java書中對怎樣實現(xiàn)一個像樣的hashCode()給出了指導。

TreeMap基于紅黑樹結(jié)構(gòu)實現(xiàn),理論上來說各方面性能都比HashMap差,使用它的唯一理由就是排序。在使用keySet對TreeMap遍歷時,按照key的compareTo方法排序輸出。

三、HashSet、TreeSet、LinkedHashSet、LinkedHashMap

HashSet是最常用的Set類,內(nèi)部借助HashMap實現(xiàn),特性可以直接參考HashMap。

TreeSet內(nèi)部借助于TreeMap實現(xiàn),同理使用它的理由也是獲得排序后的對象列表。

LinkedHashSet 與HashSet類似,區(qū)別是使用iterator遍歷時,LinkedHashSet按照對象插入的順序輸出。理論上插入時性能比HashSet差。

LinkedHashMap 與HashMap類似,區(qū)別是遍歷時,按照對象插入的順序輸出。LinkedHashMap有一個三個參數(shù)的構(gòu)造方法:

  1. public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder)

如果第三個參數(shù)設置為true,排序方式為按照訪問順序排序,可以借助該功能實現(xiàn)簡單的采用"最近最少使用"失效算法(LRU)的緩存。

四、線程安全

上面提到的類中,除了Vector和Hashtable,全部都是線程不安全的。

示例1:

  1. public static void main(String[] args) {
  2. ArrayList<Integer> list = new ArrayList<>();
  3. Thread t1 = new Thread() {
  4. public void run() {
  5. while(true) {
  6. list.add(1);
  7. }
  8. }
  9. };
  10. Thread t2 = new Thread() {
  11. public void run() {
  12. while(true) {
  13. list.add(2);
  14. }
  15. }
  16. };
  17. t1.start();
  18. t2.start();
  19. }

執(zhí)行結(jié)果:

  1. Exception in thread "Thread-1" java.lang.ArrayIndexOutOfBoundsException: 549
  2. at java.util.ArrayList.add(ArrayList.java:444)
  3. at Program$2.run(Program.java:28)

分析:ArrayList的add方法演示代碼

  1. public void add(Object o) {
  2. if(next == list.length) {
  3. list = Arrays.copyOf(list, list.length * 2);
  4. }
  5. list[next++] = o;
  6. }

ArrayList在添加對象時先判斷數(shù)組是否已滿,如果已滿則擴容。多線程狀態(tài)下,當next ==list.length-1時,兩個線程輪流切換執(zhí)行都不符合擴容條件進入下一步,此時第一個線程執(zhí)行賦值并把next+1,第二個線程執(zhí)行時next=list.length,出現(xiàn)ArrayIndexOutOfBoundsException。

示例2:

  1. public class ArrayListDemo implements Runnable {
  2. static ArrayList<Integer> list = new ArrayList<>();
  3. static CountDownLatch latch = new CountDownLatch(10000);
  4. public static void main(String[] args) throws InterruptedException {
  5. ExecutorService exec = Executors.newCachedThreadPool();
  6. for(int i = 0; i < 10000; i++) {
  7. exec.execute(new ArrayListDemo());
  8. }
  9. latch.await();
  10. System.out.println("list.size()=" + list.size());
  11. }
  12. @Override
  13. public void run() {
  14. list.add(1);
  15. latch.countDown();
  16. }
  17. }

執(zhí)行結(jié)果:

  1. list.size()=9977

示例3:

  1. public static void main(String[] args) throws InterruptedException {
  2. HashMap<String, String> map = new HashMap<>();
  3. map.put("a", "a");
  4. Iterator<String> iter = map.keySet().iterator();
  5. ExecutorService exec = Executors.newCachedThreadPool();
  6. exec.execute(new Runnable() {
  7. @Override
  8. public void run() {
  9. map.put("b", "b");
  10. }
  11. });
  12. exec.shutdown();
  13. while(iter.hasNext()) {
  14. System.out.println(iter.next());
  15. }
  16. }

執(zhí)行結(jié)果:

  1. Exception in thread "main" java.util.ConcurrentModificationException
  2. at java.util.HashMap$HashIterator.nextNode(HashMap.java:1429)
  3. at java.util.HashMap$KeyIterator.next(HashMap.java:1453)
  4. at ArrayListDemo.main(ArrayListDemo.java:34)

多線程下安全讀寫集合類有三種常見辦法:

1 JDK5以后首選concurrent包下的集合類,包括ConcurrentHashMap、CopyOnWriteArrayList和CopyOnWriteArraySet

2 讀寫操作時加鎖,使用synchronized關(guān)鍵字或者java.util.concurrent.locks下的類

3 使用Collections.synchronizedList、Collections.synchronizedMap等方法獲得線程安全集合。

總結(jié)

以上是生活随笔為你收集整理的开发高性能JAVA应用程序基础(集合篇)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 成年网站在线播放 | 久久久久女 | av永久免费在线观看 | 欧美一区二区福利视频 | 色福利在线 | 国产理论片在线观看 | 在线免费观看a级片 | 97国产精东麻豆人妻电影 | 免费观看美女裸体网站 | 不卡免费视频 | 四季av在线一区二区三区 | 有码一区 | 久色综| 天堂av资源在线 | 男人撒尿视频xvideos | 亚洲影视一区 | 天天躁日日躁狠狠躁喷水 | 日韩av专区片 | 艹少妇视频 | 男人靠女人免费视频网站 | 给我看免费高清在线观看 | 日本三级午夜理伦三级三 | 午夜伦理在线观看 | 丁香六月啪啪 | 国产精品无码久久久久高潮 | 成人精品综合 | 中文字幕免费高清在线观看 | 操操操插插插 | 激情视频91 | av尤物 | 91精品国产色综合久久不卡蜜臀 | 东方成人av在线 | 久草国产在线视频 | 天天天干 | 久久国产免费看 | 天堂av在线中文 | 日韩精品网站 | 欧美高清hd19 | 国产亚洲高清视频 | 2020av在线 | 日日夜夜免费 | 99久久婷婷国产综合精品青牛牛 | 亚洲精品福利视频 | 久久久久久久久久久国产 | 久久青娱乐 | 欧美日韩美女 | 奇米狠狠777 | 在线视频日本 | av色图在线 | 又色又爽又黄 | 亚洲啪av永久无码精品放毛片 | 操人视频免费看 | 日韩欧美激情视频 | 最新91在线| 三级黄色免费网站 | 欧美呦呦呦 | 青青草国产精品 | 4388成人网 | 视频1区 | 中国一级特黄毛片 | 亚洲国产精彩视频 | 亚洲男人网站 | 久久久久国色av免费观看性色 | 青青草国产在线视频 | 亚洲色图欧美另类 | 青娱乐在线播放 | 日韩精品极品视频在线观看免费 | 亚洲欧美高清在线 | 欧美无吗| 久久精品视频久久 | 91精品国产乱码久久 | 欧美资源网 | 精产国品一二三区 | 免费久久精品 | 2019亚洲天堂 | 成人免费视频国产免费 | 国产精品一二区在线观看 | 三级视频网站在线观看 | 人妻无码中文字幕 | 久久久精品久 | 中文字幕在线网址 | 亚洲gay视频| 亚洲人成免费电影 | 成人爽爽视频 | 懂色av懂色av粉嫩av分享吧 | 日韩美女视频一区二区 | 欧美日韩精品一区二区三区 | 少妇熟女视频一区二区三区 | 日本大尺度床戏揉捏胸 | 午夜视频福利 | 婷婷免费| 亚洲精品少妇久久久久久 | 国产精品主播在线 | 久久夜夜操 | 亚洲五月婷婷 | 欧美午夜精品理论片 | 欧美精品一区二区三区蜜臀 | 久久视频黄色 | 欧美一级网站 |