Java容器彙總【紅黑樹須要再次學習】

1,概述

2,Collection

2.1,Set【接觸比較少】

2.1.1 TreeSet

底層由TreeMap實現html

基於紅黑樹實現,支持有序性操做,例如根據一個範圍查找元素的操做。可是查找效率不如 HashSet,HashSet 查找的時間複雜度爲 O(1),TreeSet 則爲 O(logN)。java

2.1.2 HashSet【完成】

  基於哈希表實現,支持快速查找,但不支持有序性操做。而且失去了元素的插入順序信息由HashMap的數據存儲行爲有關係】,也就是說使用 Iterator 遍歷 HashSet 獲得的結果是不肯定的。node

 

  數據實現由hashmap實現, Key就是輸入的變量。value是一個統一的Object數據算法

2.1.3 LinkedHashSet【完成】

  具備 HashSet 的查找效率,且內部使用雙向鏈表維護元素的插入順序。【本質是不斷的經過hash值計算來進行下一個數值的查找】設計模式

2.2,List

  • ArrayList:基於動態數組實現,支持隨機訪問【查找複雜度O(1),本質是一個數組】。數組

  • Vector:和 ArrayList 相似,但它是線程安全的【區別sychronized修飾,作了同步處理】。緩存

  • LinkedList:基於雙向鏈表實現,只能順序訪問,可是能夠快速地在鏈表中間插入和刪除元素。【普通for遍歷每次都要重頭開始,Iterator方法是有一個光標指向這裏】不只如此,LinkedList 還能夠用做棧【LIFO】、隊列和【FIFO,能夠用來作生產者消費者設計模式】雙向隊列【集合前兩種的功能】。http://www.javashuo.com/article/p-vewneihc-hk.html安全

2.3,Queue【完成】

LinkedList:能夠用它來實現雙向隊列【實現Deque 接口】。

 

PriorityQueue:基於堆結構---minHeap

  一個基於優先級的無界優先級隊列。優先級隊列的元素按照其天然順序進行排序,或者根據構造隊列時提供的 Comparator 進行排序,具體取決於所使用的構造方法。該隊列不容許使用 null 元素也不容許插入不可比較的對象(沒有實現Comparable接口的對象)。數據結構

  Java中PriorityQueue經過二叉小頂堆實現,能夠用一棵徹底二叉樹表示(任意一個非葉子節點的權值,都不大於其左右子節點的權值)多線程

 

public class PriorityQueue<E> extends AbstractQueue<E> implements java.io.Serializable {

1>PriorityQueue是一種無界的,線程不安全的隊列
2>PriorityQueue是一種經過數組實現的,並擁有優先級的隊列
3>PriorityQueue存儲的元素要求必須是可比較的對象, 若是不是就必須明確指定比較器【能夠插入相同數據】

 須要理解堆這個數據結構就很好辦了

leftNo = parentNo*2+1

rightNo = parentNo*2+2

parentNo = (nodeNo-1)/2

 

3,Map

3.1,TreeMap

  基於紅黑樹實現。

 

 

3.2,HashMap【非線程安全】【完成】

  基於哈希表實現【這個詳見Java-HashMap實現原理

 

 

 

3.3,HashTable【遺留類,直接跳過它使用cocurrentHashMap】【完成】

  和 HashMap 相似,但它是線程安全的,這意味着同一時刻多個線程能夠同時寫入 HashTable 而且不會致使數據不一致。

  它是遺留類,不該該去使用它。如今可使用 ConcurrentHashMap 來支持線程安全,而且 ConcurrentHashMap 的效率會更高,由於 ConcurrentHashMap 引入了分段鎖

  相似於:HashTable中的鎖相似於MySQL中的表級鎖Segments所有鎖定、ConcurrentHashMap 相似於MySQL中的行級鎖單個Segment鎖定

3.4,ConcurrentHashMap【分段鎖Segments併發高效、線程安全

  HashTable容器在競爭激烈的併發環境下表現出效率低下的緣由,是由於全部訪問HashTable的線程都必須競爭同一把鎖,那假如容器裏有多把鎖,每一把鎖用於鎖容器其中一部分數據,那麼當多線程訪問容器裏不一樣數據段的數據時,線程間就不會存在鎖競爭,從而能夠有效的提升併發訪問效率,這就是ConcurrentHashMap所使用的鎖分段技術,首先將數據分紅一段一段的存儲而後給每一段數據配一把鎖,當一個線程佔用鎖訪問其中一個段數據的時候,其餘段的數據也能被其餘線程訪問。有些方法須要跨段,好比size()和containsValue(),它們可能須要鎖定整個表而而不只僅是某個段,這須要按順序鎖定全部段,操做完畢後,又按順序釋放全部段的鎖。這裏「按順序」是很重要的,不然極有可能出現死鎖,在ConcurrentHashMap內部,段數組是final的,而且其成員變量實際上也是final的,可是,僅僅是將數組聲明爲final的並不保證數組成員也是final的,這須要實現上的保證。這能夠確保不會出現死鎖,由於得到鎖的順序是固定的。

  ConcurrentHashMap是由Segment數組結構和HashEntry數組結構組成。Segment是一種 ReentrantLock,在ConcurrentHashMap裏扮演鎖的角色,HashEntry則用於存儲鍵值對數據。一個ConcurrentHashMap 裏包含一個Segment數組Segment的結構和HashMap相似,是一種數組和鏈表結構,  一個Segment裏包含一個HashEntry數組,每一個HashEntry是一個鏈表結構的元素, 每一個Segment守護者一個HashEntry數組裏的元素,當對HashEntry數組的數據進行修改時,必須首先得到它對應的Segment鎖。

特點之處:

①能夠看到ConcurrentHashMap會首先使用Wang/Jenkins hash的變種算法對元素的hashCode進行一次再哈希

② (hash >>> segmentShift) & segmentMask//向右無符號移動28位,意思是讓高4位參與到hash運算中,

Segment小鎖鎖定數據各個數據默認16個,讀

④執行 size 操做時,先不加鎖兩次結果相同,就直接使用使用這個結果;不然對每個Segment加鎖統計各個count和; 

 

JDK 1.7 使用分段鎖機制來實現併發更新操做,核心類爲 Segment,它繼承自重入鎖 ReentrantLock,併發度與 Segment 數量相等。

JDK 1.8 使用了 CAS 操做來支持更高的併發度,在 CAS 操做失敗時使用內置鎖 synchronized。

而且 JDK 1.8 的實現也在鏈表過長時會轉換爲紅黑樹。

 

3.4,LinkedHashMap【繼承HashMap,添加先後索引】【完成】

  使用雙向鏈表來維護元素的順序,順序爲插入順序或者最近最少使用(LRU)順序。 https://www.jianshu.com/p/8f4f58b4b8ab

  而後把accessOrder【LinkedHashMap特有的】設置爲false,這就跟存儲的順序有關了,LinkedHashMap存儲數據是有序的,並且分爲兩種:插入順序【head-tail】和訪問順序【0-(size-1)遍歷順序】。

  accessOrder設置爲false,表示不是訪問順序而是插入順序存儲的,這也是默認值,表示LinkedHashMap中存儲的順序是按照調用put方法插入的順序進行排序的

  header是一個Entry類型的雙向鏈表表頭,自己不存儲數據。

  插入尾部、清楚頭部

 

3.4.1 LinkedHashMap實現的LruCache【經常使用的數據緩存項】Android圖片就是用的這個

Least Recently Used

package com.cnblogs.mufasa.Map;

import java.util.LinkedHashMap;
import java.util.Map;

public class LRUCache<K, V> extends LinkedHashMap<K, V> {
    private int maxEntries;//設置的cache數據大小
    public LRUCache(int maxEntries) {
        super(16, 0.75f, true);
        this.maxEntries = maxEntries;
    }

    @Override
    protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
        //插入新數據的時候判斷是否超額
        //是,清楚head-next數據,插入新數據在head-pre
        //否,插入head-pre就行
        return size() > maxEntries;
    }
}
package com.cnblogs.mufasa.Map;

import org.w3c.dom.Node;

import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;

public class Client {
    public static void main(String[] args) {
//        HashMap<Integer,String> hm=new HashMap<>();
//        ConcurrentHashMap<Integer,String> chm=new ConcurrentHashMap<>();

        //TreeMap
//        TreeMap<Integer,String> map =new TreeMap<>();
//        map.put(3, "val");
//        map.put(2, "val");
//        map.put(1, "val");
//        map.put(5, "val");
//        map.put(4, "val");
//        System.out.println(map);


//        Integer integer=new Integer(1);
//        System.out.println(Integer.parseInt("111",2));
//        System.out.println(8^111);

//        String a1="hello";
//        String a2=new String("hello");
//        System.out.println(a1==a2);

        //
        LRUCache<String,Object> cache = new LRUCache<>(3);
        cache.put("a","abstract");
        cache.put("b","basic");
        cache.put("c","call");

        cache.put("e","hello");
        cache.put("d",null);
        cache.put(null,"null");
        cache.get("e");
        cache.put("f","滴滴滴");
        System.out.println(cache); // 輸出爲:{c=call, a=abstract, d=滴滴滴}

    }
}
/*
{null=null, e=hello, f=滴滴滴}
 */
View Code

 

3.5,WeakHashMap

3.5.1 存儲結構

WeakHashMap 的 Entry 繼承自 WeakReference,被 WeakReference 關聯的對象在下一次垃圾回收時會被回收。

WeakHashMap 主要用來實現緩存,經過使用 WeakHashMap 來引用緩存對象,由 JVM 對這部分緩存進行回收。

private static class Entry<K,V> extends WeakReference<Object> implements Map.Entry<K,V>

3.5.2 ConcurrentCache

Tomcat 中的 ConcurrentCache 使用了 WeakHashMap 來實現緩存功能。

ConcurrentCache 採起的是分代緩存:

  • 常用的對象放入 eden 中,eden 使用 ConcurrentHashMap 實現,不用擔憂會被回收(伊甸園);
  • 不經常使用的對象放入 longterm,longterm 使用 WeakHashMap 實現,這些老對象會被垃圾收集器回收。
  • 當調用 get() 方法時,會先從 eden 區獲取,若是沒有找到的話再到 longterm 獲取,當從 longterm 獲取到就把對象放入 eden 中,從而保證常常被訪問的節點不容易被回收。
  • 當調用 put() 方法時,若是 eden 的大小超過了 size,那麼就將 eden 中的全部對象都放入 longterm 中,利用虛擬機回收掉一部分不常用的對象。

核心源碼:

public final class ConcurrentCache<K, V> {

    private final int size;

    private final Map<K, V> eden;

    private final Map<K, V> longterm;

    public ConcurrentCache(int size) {
        this.size = size;
        this.eden = new ConcurrentHashMap<>(size);
        this.longterm = new WeakHashMap<>(size);
    }

    public V get(K k) {
        V v = this.eden.get(k);
        if (v == null) {
            v = this.longterm.get(k);
            if (v != null)
                this.eden.put(k, v);
        }
        return v;
    }

    public void put(K k, V v) {
        if (this.eden.size() >= size) {
            this.longterm.putAll(this.eden);
            this.eden.clear();
        }
        this.eden.put(k, v);
    }
}
View Code

 

 

4,容器中的設計模式

4.1 適配器設計模式

java.util.Arrays#asList() 能夠把數組類型轉換爲 List 類型。

A-適配器-B

@SafeVarargs
public static <T> List<T> asList(T... a)

 

4.2 迭代器模式

  讓用戶經過特定的接口訪問容器的數據,不須要了解容器內部的數據結構

  

        LinkedList<String> list = new LinkedList<>();
        list.add("a");
        list.add("b");
//        for (String item : list) {
//            System.out.println(item);
//        }
        Iterator<String> iterator=list.iterator();
        Iterator<String> iterator2=list.descendingIterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
View Code

 

4.3 引伸-生產者消費者

  Queue隊列能夠直接當作這個模式的數據結構

相關文章
相關標籤/搜索