精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

假設有一個 1G 大的 HashMap,此時用戶請求過來剛好觸發它的擴容,會怎樣?

開發 前端
如果剛好觸發擴容,那么當前用戶請求會被阻塞,因為 HashMap的底層是基于數組+鏈表(紅黑樹)來實現的,一旦它發生擴容,就需要新增一個比之前大2倍的數組,然后將元素copy到新的數組上。

簡要回答

如果剛好觸發擴容,那么當前用戶請求會被阻塞,因為 HashMap的底層是基于數組+鏈表(紅黑樹)來實現的,一旦它發生擴容,就需要新增一個比之前大2倍的數組,然后將元素copy到新的數組上。

而 1G 的 HashMap 夠大,所以擴容需要一定的時間,而擴容使用的又是當前的線程,所以用戶此時會被阻塞,等待擴容完畢。

源碼詳解、擴展追問

HashMap put方法源碼

public V put(K key, V value) {
    return putVal(hash(key), key, value, false, true);
}

先計算key的hash值,再對其put

static final int hash(Object key) {
    int h;
    //為什么要右移16位? 默認長度為2^5=16,與hash值&操作,容易獲得相同的值。
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

這里分為了三步:

  1. h=key.hashCode() //第一步 取hashCode值
  2. h^(h>>>16) //第二步 高位參與運算,減少沖突,hash計算到這里
  3. return h&(length-1); //第三步 取模運算,計算數據在桶中的位置,這里看后面的源碼

第3步(n-1)&hash原理:

  • 實際上(n-1) & hash等于 hash%n都可以得到元素在桶中的位置,但是(n-1)&hash操作更快。
  • 取余操作如果除數是 2 的整數次冪可以優化為移位操作。這也是為什么擴容時必須是必須是2的n次方

位運算(&)效率要比代替取模運算(%)高很多,主要原因是位運算直接對內存數據進行操作,不需要轉成十進制,因此處理速度非常快。

而計算hash是通過同時使用hashCode()的高16位異和低16位實現的(h >>> 16):這么做可以在數組比較小的時候,也能保證考慮到高低位都參與到Hash的計算中,可以減少沖突,同時不會有太大的開銷。

hash值其實是一個int類型,二進制位為32位,而HashMap的table數組初始化size為16,取余操作為hashCode & 15 ==> hashCode & 1111 。這將會存在一個巨大的問題,1111只會與hashCode的低四位進行與操作,也就是hashCode的高位其實并沒有參與運算,會導很多hash值不同而高位有區別的數,最后算出來的索引都是一樣的。 舉個例子,假設hashCode為1111110001,那么1111110001 & 1111 = 0001,如果有些key的hash值低位與前者相同,但高位發生了變化,如1011110001 & 1111 = 0001,1001110001 & 1111 = 0001,顯然在高位發生變化后,最后算出來的索引還是一樣,這樣就會導致很多數據都被放到一個數組里面了,造成性能退化。 為了避免這種情況,HashMap將高16位與低16位進行異或,這樣可以保證高位的數據也參與到與運算中來,以增大索引的散列程度,讓數據分布得更為均勻(個人認為是為了分布均勻)

put流程如下:

圖片圖片

// 第四個參數 onlyIfAbsent 如果是 true,那么只有在不存在該 key 時才會進行 put 操作
// 第五個參數 evict 我們這里不關心
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
               boolean evict) {
    Node<K,V>[] tab; Node<K,V> p; int n, i;
    if ((tab = table) == null || (n = tab.length) == 0)//初始判斷,初始數組為空時
        // resize()初始數組,需要進行擴容操作
        n = (tab = resize()).length;

    //這里就是上面的第三步,根據key的hash值找到數據在table中的位置
    if ((p = tab[i = (n - 1) & hash]) == null)
        //通過hash找到的數組下標,里面沒有內容就直接賦值
        tab[i] = newNode(hash, key, value, null);
    else {//如果里面已經有內容了
        Node<K,V> e; K k;
        if (p.hash == hash &&
            //hash相同,key也相同,那就直接修改value值
            ((k = p.key) == key || (key != null && key.equals(k))))
            e = p;
        else if (p instanceof TreeNode)
            //key不相同,且節點為紅黑樹,那就把節點放到紅黑樹里
            e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
        else {
        //表示節點是鏈表
            for (int binCount = 0; ; ++binCount) {
                if ((e = p.next) == null) {
                    //添加到鏈表尾部
                    p.next = newNode(hash, key, value, null);
                    if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                 //如果滿足鏈表轉紅黑樹的條件,則轉紅黑樹
                        treeifyBin(tab, hash);
                    break;
                }
                if (e.hash == hash &&
                    ((k = e.key) == key || (key != null && key.equals(k))))
                    break;
                p = e;
            }
        }
        //傳入的K元素已經存在,直接覆蓋value
        if (e != null) { // existing mapping for key
            V oldValue = e.value;
            if (!onlyIfAbsent || oldValue == null)
                e.value = value;
            afterNodeAccess(e);
            return oldValue;
        }
    }
    ++modCount;
    if (++size > threshold)//檢查元素個數是否大于閾值,大于就擴容
        resize();
    afterNodeInsertion(evict);
    return null;
}
final void treeifyBin(Node<K,V>[] tab, int hash) {
    int n, index; Node<K,V> e;
    //檢查是否滿足轉換成紅黑樹的條件,如果數組大小還小于64,則先擴容
    if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
        resize();
    else if ((e = tab[index = (n - 1) & hash]) != null) {
        TreeNode<K,V> hd = null, tl = null;
     do {
           TreeNode<K,V> p = replacementTreeNode(e, null);
           if (tl == null)
                hd = p;
            else {
                p.prev = tl;
                tl.next = p;
            }
            tl = p;
       } while ((e = e.next) != null);
       if ((tab[index] = hd) != null)
           hd.treeify(tab);
    }
}

總結put方法流程:

  1. 如果table沒有初始化就先進行初始化過程
  2. 使用hash算法計算key的索引判斷索引處有沒有存在元素,沒有就直接插入
  3. 如果索引處存在元素,則遍歷插入,有兩種情況:
  • 一種是鏈表形式就直接遍歷到尾端插入
  • 一種是紅黑樹就按照紅黑樹結構
  1. 插入鏈表的數量大于閾值8,且數組大小已經大等于64,就要轉換成紅黑樹的結構
  2. 添加成功后會檢查是否需要擴容

數組擴容源碼

//table數組的擴容操作
final Node<K,V>[] resize() {
    //引用擴容前的node數組
    Node<K,V>[] oldTab = table;
    //舊的容量
    int oldCap = (oldTab == null) ? 0 : oldTab.length;
    //舊的閾值
    int oldThr = threshold;
    //新的容量、閾值初始化為0
    int newCap, newThr = 0;
    
    //計算新容量
    if (oldCap > 0) {
        //如果舊容量已經超過最大容量,讓閾值也等于最大容量,以后不再擴容
        if (oldCap >= MAXIMUM_CAPACITY) {
            threshold = Integer.MAX_VALUE;
            return oldTab;
        }
        //沒超過最大值,就令newcap為原來容量的兩倍
        else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
                 oldCap >= DEFAULT_INITIAL_CAPACITY)
            //如果舊容量翻倍沒有超過最大值,且舊容量不小于初始化容量16,則翻倍
            newThr = oldThr << 1; // double threshold
    }
    else if (oldThr > 0) // initial capacity was placed in threshold
        //舊容量oldCap = 0時,但是舊的閾值大于0,令初始化容量設置為閾值
        newCap = oldThr;
    else {               // zero initial threshold signifies using defaults
        //兩個值都為0的時候使用默認值初始化
        newCap = DEFAULT_INITIAL_CAPACITY;
        newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
    }
    
    
    if (newThr == 0) {
        //計算新閾值,如果新容量或新閾值大于等于最大容量,則直接使用最大值作為閾值,不再擴容
        float ft = (float)newCap * loadFactor;
        newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
                  (int)ft : Integer.MAX_VALUE);
    }
    //設置新閾值
    threshold = newThr;
    
    //創建新的數組,并引用
    @SuppressWarnings({"rawtypes","unchecked"})
        Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
    table = newTab;
    
    //如果老的數組有數據,也就是是擴容而不是初始化,才執行下面的代碼,否則初始化的到這里就可以結束了
    if (oldTab != null) {
        //輪詢老數組所有數據
        for (int j = 0; j < oldCap; ++j) {
            //以一個新的節點引用當前節點,然后釋放原來的節點的引用
            Node<K,V> e;
            if ((e = oldTab[j]) != null) {//如果這個桶,不為空,說明桶中有數據
                oldTab[j] = null;
                //如果e沒有next節點,證明這個節點上沒有hash沖突,則直接把e的引用給到新的數組位置上
                if (e.next == null)
                    //確定元素在新的數組里的位置
                    newTab[e.hash & (newCap - 1)] = e;
                //如果是紅黑樹,則進行分裂
                else if (e instanceof TreeNode)
                    ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
                //說明是鏈表
                else { // preserve order
                    Node<K,V> loHead = null, loTail = null;
                    Node<K,V> hiHead = null, hiTail = null;
                    Node<K,V> next;
                    //從這條鏈表上第一個元素開始輪詢,如果當前元素新增的bit是0,則放在當前這條鏈表上
                    //如果是1,則放在"j+oldcap"這個位置上,生成“低位”和“高位”兩個鏈表
                    do {
                        next = e.next;
                        if ((e.hash & oldCap) == 0) {
                            if (loTail == null)
                                loHead = e;
                            else
                                //元素是不斷的加到尾部的
                                loTail.next = e;
                            //新增的元素永遠是尾元素
                            loTail = e;
                        }
                        else {
                            //高位的鏈表與低位的鏈表處理邏輯一樣,不斷的把元素加到鏈表尾部
                            if (hiTail == null)
                                hiHead = e;
                            else
                                hiTail.next = e;
                            hiTail = e;
                        }
                    } while ((e = next) != null);
                    //低位鏈表放到j這個索引的位置上
                    if (loTail != null) {
                        loTail.next = null;
                        newTab[j] = loHead;
                    }
                    //高位鏈表放到(j+oldCap)這個索引的位置上
                    if (hiTail != null) {
                        hiTail.next = null;
                        newTab[j + oldCap] = hiHead;
                    }
                }
            }
        }
    }
    return newTab;
}

顯然,HashMap的擴容機制,就是當達到擴容條件時會進行擴容。擴容條件就是當HashMap中的元素個數超過臨界值時就會自動擴容(threshold = loadFactor * capacity)。如果是初始化擴容,只執行resize的前半部分代碼,但如果是隨著元素的增加而擴容,HashMap需要重新計算oldTab中每個值的位置,即重建hash表,隨著元素的不斷增加,HashMap會發生多次擴容,這樣就會非常影響性能。所以一般建議創建HashMap的時候指定初始化容量

但是當使用HashMap(int initialCapacity)來初始化容量的時候,HashMap并不會使用傳進來的initialCapacity直接作為初始容量。JDK會默認計算一個相對合理的值當做初始容量。所謂合理值,其實是找到第一個比用戶傳入的值大的2的冪。也就是說,當new HashMap(7)創建HashMap的時候,JDK會通過計算,創建一個容量為8的Map;當new HashMap(9)創建HashMap的時候,JDK會通過計算,創建一個容量為16的Map。當然了,當創建一個HashMap時,表的大小并不會立即分配,而是在第一次put元素時進行分配,并且分配的大小會是大于或等于初始容量的最小的2的冪。

一般來說,initialCapacity = (需要存儲的元素個數 / 負載因子) + 1。注意負載因子(即 loaderfactor)默認為 0.75,如果暫時無法確定初始值大小,請設置為 16(即默認值)。HashMap 需要放置 1024 個元素,由于沒有設置容量初始大小,隨著元素增加而被迫不斷擴容,resize() 方法總共會調用 8 次,反復重建哈希表和數據遷移。當放置的集合元素個數達千萬級時會影響程序性能。

//初始化容量
public HashMap(int initialCapacity) {
    this(initialCapacity, DEFAULT_LOAD_FACTOR);
}

public HashMap(int initialCapacity, float loadFactor) {
    //保證initialCapacity在合理范圍內,大于0小于最大容量
    if (initialCapacity < 0)
        throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity);
    if (initialCapacity > MAXIMUM_CAPACITY)
          initialCapacity = MAXIMUM_CAPACITY;
    if (loadFactor <= 0 || Float.isNaN(loadFactor))
           throw new IllegalArgumentException("Illegal load factor: " + loadFactor);
    this.loadFactor = loadFactor;
    this.threshold = tableSizeFor(initialCapacity);
}

static final int tableSizeFor(int cap) {
    int n = cap - 1;
    //|=計算方式:兩個二進制對應位都為0時,結果等于0,否則結果等于1;
    n |= n >>> 1;
    n |= n >>> 2;
    n |= n >>> 4;
    n |= n >>> 8;
    n |= n >>> 16;
    return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}
/**
 * 紅黑樹分裂方法
 */
final void split(HashMap<K,V> map, Node<K,V>[] tab, int index, int bit) {
     //當前這個節點的引用,即這個索引上的樹的根節點
     TreeNode<K,V> b = this;
     // Relink into lo and hi lists, preserving order
     TreeNode<K,V> loHead = null, loTail = null;
     TreeNode<K,V> hiHead = null, hiTail = null;
     //高位低位的初始樹節點個數都設成0
     int lc = 0, hc = 0;
     for (TreeNode<K,V> e = b, next; e != null; e = next) {
            next = (TreeNode<K,V>)e.next;
           e.next = null;
           //bit=oldcap,這里判斷新bit位是0還是1,如果是0就放在低位樹上,如果是1就放在高位樹上,這里先是一個雙向鏈表
           if ((e.hash & bit) == 0) {
               if ((e.prev = loTail) == null)
                    loHead = e;
               else
                    loTail.next = e;
               loTail = e;
               ++lc;
            }
            else {
                if ((e.prev = hiTail) == null)
                    hiHead = e;
                else
                    hiTail.next = e;
                hiTail = e;
                ++hc;
            }
       }
 
       if (loHead != null) {
            if (lc <= UNTREEIFY_THRESHOLD)
                //!!!如果低位的鏈表長度小于閾值6,則把樹變成鏈表,并放到新數組中j索引位置
                tab[index] = loHead.untreeify(map);
            else {
                tab[index] = loHead;
                //高位不為空,進行紅黑樹轉換
                if (hiHead != null) // (else is already treeified)
                    loHead.treeify(tab);
            }
        }
        if (hiHead != null) {
            if (hc <= UNTREEIFY_THRESHOLD)
                tab[index + bit] = hiHead.untreeify(map);
            else {
                tab[index + bit] = hiHead;
                if (loHead != null)
                    hiHead.treeify(tab);
            }
        }
}
/**
 * 將樹轉變為單向鏈表
 */
final Node<K,V> untreeify(HashMap<K,V> map) {
     Node<K,V> hd = null, tl = null;
     for (Node<K,V> q = this; q != null; q = q.next) {
          Node<K,V> p = map.replacementNode(q, null);
          if (tl == null)
                hd = p;
          else
               tl.next = p;
          tl = p;
      }
     return hd;
}
/**
 * 鏈表轉換為紅黑樹,會根據紅黑樹特性進行顏色轉換、左旋、右旋等
 */
final void treeify(Node<K,V>[] tab) {
      TreeNode<K,V> root = null;
      for (TreeNode<K,V> x = this, next; x != null; x = next) {
             next = (TreeNode<K,V>)x.next;
           x.left = x.right = null;
           if (root == null) {
                x.parent = null;
                x.red = false;
                root = x;
           }
           else {
                K k = x.key;
                int h = x.hash;
                Class<?> kc = null;
                for (TreeNode<K,V> p = root;;) {
                    int dir, ph;
                    K pk = p.key;
                    if ((ph = p.hash) > h)
                         dir = -1;
                    else if (ph < h)
                         dir = 1;
                    else if ((kc == null &&
                              (kc = comparableClassFor(k)) == null) ||
                             (dir = compareComparables(kc, k, pk)) == 0)
                          dir = tieBreakOrder(k, pk);
 
                    TreeNode<K,V> xp = p;
                    if ((p = (dir <= 0) ? p.left : p.right) == null) {
                        x.parent = xp;
                        if (dir <= 0)
                            xp.left = x;
                        else
                            xp.right = x;
                        //進行左旋、右旋調整
                        root = balanceInsertion(root, x);
                        break;
                    }
                 }
            }
        }
        moveRootToFront(tab, root);
}

總結HashMap的實現:

  1. HashMap的內部存儲結構其實是 數組+ 鏈表+ 紅黑樹 的結合。當實例化一個HashMap時,會初始化initialCapacity和loadFactor,此時還不會創建數組
  2. 在put第一對映射關系時,系統會創建一個長度為initialCapacity(默認為16)的Node數組,這個長度在哈希表中被稱為容量(Capacity),在這個數組中可以存放元素的位置我們稱之為“桶”(bucket),每個bucket都有自己的索引,系統可以根據索引快速的查找bucket中的元素。
  3. 每個bucket中存儲一個元素,即一個Node對象,但每一個Node對象可以帶一個引用變量next,用于指向下一個元素,因此,在一個桶中,就有可能生成一個Node鏈。也可能是一個一個TreeNode對象,每一個TreeNode對象可以有兩個葉子結點left和right,因此,在一個桶中,就有可能生成一個TreeNode樹。而新添加的元素作為鏈表的last,或樹的葉子結點

總結HashMap的擴容和樹形化:

  1. 當HashMap中的元素個數超過數組大小(數組總大小length,不是數組中個數size)*loadFactor 時,就會進行數 組擴容,loadFactor的默認值(DEFAULT_LOAD_FACTOR)為0.75,這是一個折中的取值。也就是說,默認情況下,數組大小(DEFAULT_INITIAL_CAPACITY)為16,那么當HashMap中元素個數超過16*0.75=12(這個值就是代碼中的threshold值,也叫做臨界值)的時候,就把數組的大小擴展為 2*16=32,即擴大一倍,然后重新計算每個元素在數組中的位置,而這是一個非常消耗性能的操作,所以如果我們已經預知HashMap中元素的個數,那么預設元素的個數能夠有效的提高HashMap的性能
  2. 當HashMap中的其中一個鏈的對象個數如果達到了8個,此時如果capacity沒有達到64,那么HashMap會先擴容解決,如果已經達到了64,那么這個鏈會變成樹,結點類型由Node變成TreeNode類型。當然,如果當映射關系被移除后,下次resize方法時判斷樹的結點個數低于6個,也會把樹再轉為鏈表。

即當數組的某一個索引位置上的元素以鏈表形式存在的數據個數>8且當前數組的長度>64時,此時此索引位置上的所有數據改為使用紅黑樹存儲

HashMap擴容過程是怎樣的?(簡要版)

1.8擴容機制:當元素個數大于threshold時,會進行擴容,使用2倍容量的數組代替原有數組。采用尾插入的方式將原數組元素拷貝到新數組。1.8擴容之后鏈表元素相對位置沒有變化,而1.7擴容之后鏈表元素會倒置。

1.7鏈表新節點采用的是頭插法,這樣在線程一擴容遷移元素時,會將元素順序改變,導致兩個線程中出現元素的相互指向而形成循環鏈表,1.8采用了尾插法,避免了這種情況的發生。

原數組的元素在重新計算hash之后,因為數組容量n變為2倍,那么n-1的mask范圍在高位多1bit。在元素拷貝過程不需要重新計算元素在數組中的位置,只需要看看原來的hash值新增的那個bit是1還是0,是0的話索引沒變,是1的話索引變成“原索引+oldCap”(根據e.hash & oldCap == 0判斷) 。這樣可以省去重新計算hash值的時間,而且由于新增的1bit是0還是1可以認為是隨機的,因此resize的過程會均勻的把之前的沖突的節點分散到新的bucket。

HashMap 擴容機制的性能影響

擴容觸發條件:當 HashMap 中的元素數量超過 容量x負載因子 時,會觸發擴容。擴容會將容量擴展為當前容量的兩倍,并將所有鍵值對重新分配到新的桶(bucket)中。

性能影響:擴容是一個耗時的操作,因為它需要重新計算每個鍵的哈希值,并將鍵值對重新分配到新的桶中。因此,頻繁的擴容會顯著影響性能,特別是在存儲大量數據時。

為什么 HashMap 在擴容時采用2的n次方倍?

Hashmap 采用2的n次方倍作為容量,主要是為了提高哈希值的分布均勻性和哈希計算的效率

HasMap通過(n - 1)&hash來計算元素存儲的索引位置,這種位運算只有在數組容量是2的n次方時才能確保案引均勻分布,位運算的效率高于取模運算(hash%n),提高了哈希計算的讀度

且當 hashMap擴容時,通過容量為2的n次方,擴容時只需通過簡單的位運算判斷是否需要遷移,這減少了重新計算哈希值的開銷,提升了 rehash 的效率。

為什么建議設置HashMap的容量?

HashMap有擴容機制,就是當達到擴容條件時會進行擴容。擴容條件就是當HashMap中的元素個數超過臨界值時就會自動擴容(threshold = loadFactor * capacity)。

如果沒有設置初始容量大小,隨著元素的不斷增加,HashMap會發生多次擴容。而HashMap每次擴容都需要重建hash表,非常影響性能。所以建議開發者在創建HashMap的時候指定初始化容量。

HashMap默認加載因子是多少?為什么是 0.75?

先看下HashMap的默認構造函數:

int threshold;             // 容納鍵值對的最大值
final float loadFactor;    // 負載因子
int modCount;  
int size;

Node[] table的初始化長度length為16,默認的loadFactor是0.7。

為什么默認負載因子是 0.75?官方答案如下:

As a general rule, the default load factor (.75) offers a good tradeoff between time and space costs. Higher values decrease the space overhead but increase the lookup cost (reflected in most of the operations of the HashMap class, including get and put). The expected number of entries in the map and its load factor should be taken into account when setting its initial capacity, so as to minimize the number of rehash operations. If the initial capacity is greater than the maximum number of entries divided by the load factor, no rehash operations will ever occur.

上面的意思,簡單來說是默認負載因子為 0.75,是因為它提供了空間和時間復雜度之間的良好平衡。 負載因子太低會導致大量的空桶浪費空間,負載因子太高會導致大量的碰撞,降低性能。0.75 的負載因子在這兩個因素之間取得了良好的平衡。也就是說官方并未對負載因子為 0.75 做過的的解釋,只是大概的說了一下,0.75 是空間和時間復雜度的平衡,但更多的細節是未做說明的,Stack Overflow 進行了負載因子的科學推測,感興趣的可以學習學習

也就是說所,0.75是對空間和時間效率的一個平衡選擇,根據泊松分布,loadFactor 取0.75碰撞最小。一般不會修改,除非在時間和空間比較特殊的情況下 :

  • 如果內存空間很多而又對時間效率要求很高,可以降低負載因子Load factor的值 。
  • 如果內存空間緊張而對時間效率要求不高,可以增加負載因子loadFactor的值,這個值可以大于1。
責任編輯:武曉燕 來源: sevenCoding
相關推薦

2025-01-08 07:00:00

MySQL數據庫判重

2022-03-09 07:21:10

網絡攻擊5G

2025-05-26 01:55:00

HashMap擴容Redis

2019-06-19 09:56:39

地震預警系統

2019-03-28 06:31:01

2018-07-06 15:03:29

5G標準網絡

2018-01-31 08:12:55

運營商流量費上網流量

2021-11-05 07:59:25

HashMapJava知識總結

2022-02-09 22:49:06

1G移動通信

2019-03-10 15:54:22

5G通信4G

2016-12-21 15:33:11

中國移動4G尚冰

2020-03-26 17:00:53

HashMapputJava

2015-10-10 11:09:48

NFVNFVI網絡虛擬化

2020-06-23 14:20:08

5G網絡國家工業革命

2019-03-04 08:26:47

1G5G通信

2010-04-07 17:18:56

郵件服務器

2025-03-07 09:18:10

2019-07-04 15:08:35

5G4G毫米波

2018-06-05 13:33:16

SDN5GNFV

2018-01-04 16:04:35

圓環放大動畫
點贊
收藏

51CTO技術棧公眾號

欧美性大战久久久久久久蜜臀| heyzo一本久久综合| 不卡伊人av在线播放| aaa黄色大片| 亚洲欧洲自拍| 亚洲免费看黄网站| 日韩高清av电影| www.xxxx国产| 视频一区欧美精品| 欧美日本精品在线| 欧美激情 一区| silk一区二区三区精品视频 | 激情av综合网| 国内精品久久久久久久久| 五月天婷婷丁香网| 色爱综合av| 日韩午夜电影av| xxxx一级片| 大菠萝精品导航| 亚洲日本青草视频在线怡红院| 免费精品视频一区| 黄色av中文字幕| 久久精品国产久精国产| 青青a在线精品免费观看| 麻豆视频在线免费看| 精品国产一区二区三区| 亚洲成人a级网| 毛片毛片毛片毛片毛| 色综合一本到久久亚洲91| 亚洲成人综合网站| 天天做天天爱天天高潮| yw在线观看| 久久亚洲一区二区三区四区| 国产精品三区四区| www.五月激情| 国产一区不卡精品| 成人淫片在线看| 自拍偷拍第八页| 日产国产欧美视频一区精品| 欧美一性一乱一交一视频| 国产精彩视频在线| 国产精品啊v在线| 欧美精品一区二区三区国产精品| 久久久久久成人网| 不卡中文字幕| 色爱精品视频一区| 中文字幕免费在线看线人动作大片| 欧美色图五月天| 日韩高清av在线| 国产又粗又长又爽| 欧美有码在线| 国产视频综合在线| 亚洲熟妇一区二区三区| 亚洲国产最新| 国产午夜精品全部视频播放| 亚洲人成人无码网www国产| 蜜桃国内精品久久久久软件9| 亚洲激情自拍图| 欧美成人三级伦在线观看| 精品少妇3p| 国产视频综合在线| 无码一区二区三区在线| 欧美偷拍自拍| 色偷偷88888欧美精品久久久 | 亚洲综合伊人久久| 日韩视频一二区| 亚洲国产精品女人久久久| 亚洲蜜桃精久久久久久久久久久久| 国产精品美女在线观看直播| 亚洲激情自拍图| 人妻体内射精一区二区| 欧美色图一区| 另类图片亚洲另类| 国产精品111| 日韩在线观看一区二区| 91精品久久久久久久久青青| 精品久久人妻av中文字幕| 成人高清伦理免费影院在线观看| 欧美裸体网站| 免费黄色在线观看| 亚洲www啪成人一区二区麻豆| 国产成人黄色片| 国产精品原创视频| 日韩欧美黄色影院| 人妻大战黑人白浆狂泄| 91综合久久| 国内免费久久久久久久久久久| 97久久久久久久| 久久福利视频一区二区| 99精品国产高清一区二区| 偷拍自拍在线视频| 国产精品久久久久婷婷二区次| 欧美这里只有精品| 精品亚洲美女网站| 日韩欧美自拍偷拍| 国产激情第一页| 日韩理论电影| 91av在线播放| 丰满熟女人妻一区二区三| 国产精品66部| 婷婷四月色综合| 国产嫩草在线视频| 欧美性生活影院| 精品熟女一区二区三区| 99久久久久| 2023亚洲男人天堂| 国产国语亲子伦亲子| 久久久精品日韩欧美| 免费观看亚洲视频| 成人四虎影院| 精品一区二区三区四区| 国产a免费视频| 奇米色一区二区三区四区| 精品国产乱码久久久久软件| 国产原创在线观看| 欧美综合一区二区三区| 亚洲色图欧美日韩| 一区二区三区午夜探花| 国产精品亚发布| 三区在线视频| 午夜精品123| 麻豆精品国产传媒| 香蕉综合视频| 国产精品激情自拍| 欧美扣逼视频| 精品成人国产在线观看男人呻吟| 亚洲一区二区图片| 欧美激情欧美| 国产日韩在线看| 国产高清免费av在线| 欧美午夜久久久| 岛国精品资源网站| 亚洲性人人天天夜夜摸| 亚洲一区二区中文| 黄色网在线看| 51久久夜色精品国产麻豆| 亚洲不卡的av| 麻豆传媒一区二区三区| 亚洲永久激情精品| 日韩成人综合网| 深夜福利日韩在线看| 天天天天天天天干| 国产日韩成人精品| 北条麻妃av高潮尖叫在线观看| 四虎影视精品| 51久久精品夜色国产麻豆| 深爱五月激情五月| 亚洲成人免费视| 亚洲色偷偷色噜噜狠狠99网| 亚洲精品社区| 久久免费看av| 免费成人直播| 国产午夜精品一区理论片飘花| 精品不卡一区二区| 国产亚洲福利社区一区| 国产wwwxx| 999精品一区| 亚洲自拍偷拍视频| 国产白丝在线观看| 日韩av资源在线播放| 中文字幕在线播| 国产欧美日韩三级| 亚洲另类第一页| 午夜精品剧场| 国产伦精品一区二区三区| 午夜伦理福利在线| 国产亚洲欧洲高清| 国产视频第一页| 亚洲一区二区3| 91精品国产自产| 奇米精品一区二区三区在线观看一| 一区二区三区av| 成人精品动漫一区二区三区| 91爱爱小视频k| 成年人在线观看视频| 7777精品伊人久久久大香线蕉| a级片在线观看免费| av资源站一区| 牛夜精品久久久久久久| 国产一区日韩一区| 日韩精品一区二区三区丰满| 999精品视频在线观看| 欧美激情免费在线| 每日更新av在线播放| 777午夜精品视频在线播放| 国产精品成人久久| 国产精品毛片a∨一区二区三区| 中文字幕第10页| 国产日韩1区| 熟妇熟女乱妇乱女网站| 国产精品香蕉| 国产欧美一区二区| 免费一二一二在线视频| 精品国产一区二区三区久久| 香蕉久久国产av一区二区| 欧美日本视频在线| 日韩欧美大片在线观看| 中文字幕制服丝袜一区二区三区| 人妻激情偷乱频一区二区三区| 日韩中文字幕麻豆| 日韩 欧美 视频| 手机在线电影一区| 免费日韩av电影| 亚洲日本视频在线| 国产日韩精品一区二区| 一区二区精品伦理...| 美乳少妇欧美精品| 成年人视频免费在线观看| 欧美精品一区二区三区视频| 国产一区二区小视频| 欧美性生活大片免费观看网址| 国产乱国产乱老熟300| 日本一区免费视频| 中文文字幕文字幕高清| 国产精品一区二区视频| 亚洲77777| 玖玖在线精品| 免费国产黄色网址| 午夜精品视频| 亚洲毛片在线免费观看| 国产精品拍拍拍| 国产精品vip| 成年人免费观看的视频| 视频精品在线观看| 久久99精品久久久久久青青日本 | 在线观看h网| 在线精品国产成人综合| 九色视频在线播放| 日韩成人黄色av| 日韩在线一区二区三区四区| 日韩免费高清av| 99久久国产热无码精品免费| 欧美日韩久久久| 中文字幕 视频一区| 一本色道久久综合狠狠躁的推荐 | 国产一区二区三区无遮挡| 国产一区二区三区免费在线| 国产精品偷伦一区二区| 蜜桃视频成人m3u8| 欧美中文字幕不卡| 在线免费看v片| 国内精品免费在线观看| mm131国产精品| 欧美96一区二区免费视频| 午夜精品在线免费观看| 秋霞影院一区二区| 国产三级三级看三级| 另类的小说在线视频另类成人小视频在线 | 国产小视频免费在线网址| 日韩国产高清污视频在线观看| 黄色一级a毛片| 亚洲成人动漫在线播放| 亚洲欧美日韩动漫| 亚洲视频精品在线| www.亚洲免费| 色偷偷偷亚洲综合网另类| 久操视频在线| 精品中文字幕在线观看| sm在线播放| 欧美怡春院一区二区三区| 在线最新版中文在线| 国产精品第2页| 国产精品美女久久久久人| 999久久久| 日本女人性生活视频| 久久激情五月激情| 精品人妻一区二区三区免费| 国产成人精品一区二区三区四区 | 亚洲综合网狠久久| 国产精品一区视频| 免费欧美一区| 永久久久久久| 亚洲特级毛片| 国产精品69页| 国产美女娇喘av呻吟久久| www.com日本| 国产校园另类小说区| 久久国产高清视频| 日韩天堂在线| 久久精品国产一区二区电影| 色黄网站在线观看| 亲子乱一区二区三区电影| 久久亚洲资源中文字| 7777精品伊久久久大香线蕉语言| 久久国产精品色av免费看| 日韩精品一区二区三区丰满| 欧美aⅴ99久久黑人专区| 97国产在线播放| 激情五月激情综合网| 少妇激情一区二区三区视频| 国产日产欧产精品推荐色| 国产探花在线播放| 色天使色偷偷av一区二区| 国产女同91疯狂高潮互磨| 亚洲精品电影网| 在线视频婷婷| 性色av一区二区三区| 久久99国产精品二区高清软件| 国产精品一区二区三区在线| 久久综合电影| 国产一区二区三区精彩视频 | 星空大象在线观看免费播放| 国产精品日韩成人| 国产精品女视频| 日本日本精品二区免费| 国产视频二区在线观看| 日韩中文第一页| 色吧亚洲日本| 亚洲一区二区三区乱码aⅴ| 九九精品久久| 欧美激情亚洲天堂| 美女一区二区久久| 波多野结衣av在线免费观看| 亚洲精品成a人| 亚洲中文无码av在线| 亚洲国产日韩一区| 伊人影院在线视频| 国产精品美女呻吟| 国产精品第6页| 色av一区二区| 天堂在线视频免费| 欧美日韩国产成人| 伊人久久大香线蕉综合影院首页| 欧美一区1区三区3区公司| 在线观看日韩av电影| 成年人性生活视频| 国产精品进线69影院| 亚洲三区在线观看| 成人性生交大片免费看中文视频| 日本特级黄色大片| 美日韩一级片在线观看| 蜜桃av乱码一区二区三区| 色综合久久99| 日本亚洲欧美| 国产91精品视频在线观看| 久久草在线视频| 国产欧美日韩网站| 成人a区在线观看| 日本熟妇成熟毛茸茸| 亚洲第一视频网| 成人影音在线| 国语精品中文字幕| 亚洲在线网站| 欧美色图亚洲激情| 色妞www精品视频| 黄色美女网站在线观看| 国产精品成人久久久久| 欧美精选视频在线观看| 男人插女人下面免费视频| 国产欧美日韩三级| 国产一级片一区二区| 综合久久五月天| 日韩亚洲国产免费| 欧美做受777cos| 国产69精品久久久久777| 久久午夜无码鲁丝片午夜精品| 欧美zozozo| 欧美调教sm| 台湾成人av| 国产一区二区美女| 久久免费视频99| 亚洲精品久久久久| 久久天堂av| 宅男噜噜99国产精品观看免费| 国产一区二区三区四区五区入口| 久久国产精品波多野结衣| 亚洲精品不卡在线| 欧美专区福利免费| 在线看成人av电影| 国产成人在线免费| 久久精品无码av| 日韩在线视频国产| aiai久久| 欧美一级黄色影院| **欧美大码日韩| 天天操天天插天天射| 国产精品久久久久不卡| 影音先锋成人在线电影| 午夜不卡久久精品无码免费| 欧洲国产伦久久久久久久| 182tv在线播放| 久久精品99| 国产在线视频精品一区| 日本熟妇乱子伦xxxx| 中文字幕亚洲无线码a| 9l视频自拍蝌蚪9l视频成人| 男女视频一区二区三区| 一区二区视频免费在线观看| 欧美女v视频| 99热最新在线| 日本女优在线视频一区二区| 久久99久久98精品免观看软件| 亚洲成人中文字幕| 亚洲精品一区二区在线播放∴| 日本中文字幕网址| 亚洲色图视频网| 欧美美女搞黄| 国产伦精品一区二区三区视频孕妇 | 欧美成年人视频网站| 中文精品一区二区|