<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                [TOC] ## 初始化HashMap 新建一個HashMap(其實就是創建一個Entry數組) ``` Map<String, Object> map = new HashMap<String, Object>(); ``` 初始化HashMap(new HashMap())時,會將HashMap的初始容量設置為16,將負載因子設為0.75 ``` //默認容量大小 static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16 //默認負載因子 static final float DEFAULT_LOAD_FACTOR = 0.75f; public HashMap() { this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR); } ``` 然后繼續初始化HashMap ``` public HashMap(int initialCapacity, float loadFactor) { if (initialCapacity < 0) throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity); //HashMap最大容量是2的30次方 1073741824 if (initialCapacity > MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY; if (loadFactor <= 0 || Float.isNaN(loadFactor)) throw new IllegalArgumentException("Illegal load factor: " + loadFactor); this.loadFactor = loadFactor; //初始化HashMap容量的閾值: 16;如果hashMap的容量大于16后,就會hashMap的擴容 threshold = initialCapacity; init(); } ``` 初始化完成后,向HashMap中設置值,即put方法 ## 向HashMap中設置值 put(K key, V value) ``` public V put(K key, V value) { if (table == EMPTY_TABLE) { /** * (1) 初始化table,new一個容量大小為16的Entry[]數組 * (2) 設置閾值threshold = 16*0.75(容量*負載因子) = 12 * (3) 如果有必要還會設置散列掩碼值hashing mask value */ inflateTable(threshold); } // 如果key為空, put一個key為null的值 if (key == null) return putForNullKey(value); //計算key的hash值 int hash = hash(key); //計算Entry數組的下標 int i = indexFor(hash, table.length); //如果已經有了相同的key,則使用新值替換舊值,并返回舊值 // table[i]有可能是一個鏈表 for (Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } modCount++; //添加key value addEntry(hash, key, value, i); return null; } ``` 這里有個比較重要的地方 ``` for (Entry<K,V> e = table[i]; e != null; e = e.next) ``` 獲取某個下標的HashMap值,可能獲取到多個Entry數據,這個Entry數據是由鏈表組成,所有這里需要用到for循環,就是因為此處,會導致HashMap線程不安全(后面會具體說明原因); addEntry()源碼,如果Entry數組的實際容量大小大于等于閾值(12),則需要對hashMap進行擴容(即新建一個Entry數組,其大小為現在數組的兩倍大小),并把原Entry數組中的內容移到新Entry數組中,并重新計算key的hash值,作為新Entry數組的下標(參照下面resize()方法);如果Entry數組的實際容量大小小于閾值(12),則在原Entry數組中新添加一組數據。 ``` void addEntry(int hash, K key, V value, int bucketIndex) { if ((size >= threshold) && (null != table[bucketIndex])) { //擴容Entry數組 resize(2 * table.length); hash = (null != key) ? hash(key) : 0; //新Entry數組的下標 bucketIndex = indexFor(hash, table.length); } //向Entry數組中添加一組數據 createEntry(hash, key, value, bucketIndex); } ``` 擴容Entry數組方法:resize() ``` void resize(int newCapacity) { Entry[] oldTable = table; int oldCapacity = oldTable.length; if (oldCapacity == MAXIMUM_CAPACITY) { threshold = Integer.MAX_VALUE; return; } //新建一個Entry數組 Entry[] newTable = new Entry[newCapacity]; //將原數組的數據移到新數組中 transfer(newTable, initHashSeedAsNeeded(newCapacity)); table = newTable; threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1); } ``` 將原數組移到新數組中,并重新計算每個key的hash值 ``` void transfer(Entry[] newTable, boolean rehash) { int newCapacity = newTable.length; for (Entry<K,V> e : table) { while(null != e) { Entry<K,V> next = e.next; if (rehash) { e.hash = null == e.key ? 0 : hash(e.key); } int i = indexFor(e.hash, newCapacity); e.next = newTable[i]; newTable[i] = e; e = next; } } } ``` 向Entry數組中新增一組數據 ``` void createEntry(int hash, K key, V value, int bucketIndex) { Entry<K,V> e = table[bucketIndex]; //新建一個Entry對象,并賦值,然后添加到table數組中 table[bucketIndex] = new Entry<>(hash, key, value, e); //添加完數據后,數組大小+1 size++; } ``` 向HashMap中添加key、value的流程基本就完成了。 ## 從HashMap中獲取值 get(Object key) ``` public V get(Object key) { if (key == null) return getForNullKey(); Entry<K,V> entry = getEntry(key); return null == entry ? null : entry.getValue(); } ``` 獲取key對應的Entry對象 ``` final Entry<K,V> getEntry(Object key) { if (size == 0) { return null; } int hash = (key == null) ? 0 : hash(key); for (Entry<K,V> e = table[indexFor(hash, table.length)]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) return e; } return null; } ``` 管中窺豹,其他方法不展開了。 ## 為什么HashMap不是線程安全的 (1)put操作線程不安全 在多線程的情況下,線程A和線程B同時對一個map的數組位置(table[1])進行put操作,兩個線程同時得到table[1]鏈表的頭結點,線程A執行完put操作后,將新值存儲到了頭結點的位置,而此時線程B才執行完put操作,則線程B存儲的值會覆蓋掉線程A存儲的值,這樣會導致線程A存儲的值丟失。 (2)刪除鍵值時線程不安全:原理同上 (3)當數組容量超過閾值時,同resize數組,從新建一個比原來容量大一倍的數組,此時當多個線程同時操作一個map的resize時,最后一個線程的resize會覆蓋掉前面所有線程的resize操作,導致其他線程的數據都會丟失。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看