/** * @param <U> the class of the objects in the original array * @param <T> the class of the objects in the returned array * @param original the array to be copied * @param newLength the length of the copy to be returned * @param newType the class of the copy to be returned * @return a copy of the original array, truncated or padded with nulls * to obtain the specified length */ publicstatic <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) { @SuppressWarnings("unchecked") //创建一个空数组 T[] copy = ((Object)newType == (Object)Object[].class) ? (T[]) new Object[newLength] : (T[]) Array.newInstance(newType.getComponentType(), newLength); //复制数组 System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; }
这里又用到了System.arraycopy方法,我们再来看一下
1 2 3 4 5 6 7 8
/** * @param src the source array. * @param srcPos starting position in the source array. * @param dest the destination array. * @param destPos starting position in the destination data. * @param length the number of array elements to be copied. */ publicstaticnativevoidarraycopy(Object src, int srcPos, Object dest, int destPos, int length);
ArrayList的扩容机制
被动扩容
1 2 3 4 5 6 7 8 9 10
/** * 将一个元素加到列表尾部 * @param e element to be appended to this list */ publicbooleanadd(E e){ //当前capacity为10,size为0,调用ensureCapacityInternal方法检查是否需要扩容 ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; returntrue; }
/** * 将一个键值对放入table中,若该key已经存在,则将对应value更新为新的value * * @param key key with which the specified value is to be associated * @param value value to be associated with the specified key */ public V put(K key, V value){ return putVal(hash(key), key, value, false, true); }
/** * Implements Map.put and related methods. * * @param hash hash for key * @param key the key * @param value the value to put * @param onlyIfAbsent if true, don't change existing value * @param evict if false, the table is in creation mode. * @return previous value, or null if none */ final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict){ Node<K,V>[] tab; Node<K,V> p; int n, i; //若当前table为空或长度为0,则进行resize扩容 if ((tab = table) == null || (n = tab.length) == 0) n = (tab = resize()).length; //若该key对应的table项为空,则创建新key-value对 if ((p = tab[i = (n - 1) & hash]) == null) tab[i] = newNode(hash, key, value, null); else { Node<K,V> e; K k; //若该key存在,覆盖value值 if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) e = p; //若该节点为树节点,则调用putTreeVal在红黑树插入key-value对 elseif (p instanceof TreeNode) 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); //若插入后的链表大小大于TREEIFY_THRESHOLD,则转换为红黑树 if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st treeifyBin(tab, hash); break; } //若该key值存在,则覆盖value值 if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) break; p = e; } } if (e != null) { // existing mapping for key V oldValue = e.value; if (!onlyIfAbsent || oldValue == null) e.value = value; afterNodeAccess(e); return oldValue; } } ++modCount; //若当前size大于threshold,扩容 if (++size > threshold) resize(); afterNodeInsertion(evict); returnnull; }
/** * The largest possible (non-power of two) array size. * Needed by toArray and related methods. */ staticfinalint MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
/** * The default concurrency level for this table. Unused but * defined for compatibility with previous versions of this class. */ privatestaticfinalint DEFAULT_CONCURRENCY_LEVEL = 16;
/** * The load factor for this table. */ privatestaticfinalfloat LOAD_FACTOR = 0.75f;
/** * The bin count threshold for using a tree rather than list for a bin. */ staticfinalint TREEIFY_THRESHOLD = 8;
/** * The bin count threshold for untreeifying a (split) bin during a * resize operation. Should be less than TREEIFY_THRESHOLD, and at * most 6 to mesh with shrinkage detection under removal. */ staticfinalint UNTREEIFY_THRESHOLD = 6;
/** * The smallest table capacity for which bins may be treeified. * (Otherwise the table is resized if too many nodes in a bin.) * The value should be at least 4 * TREEIFY_THRESHOLD to avoid * conflicts between resizing and treeification thresholds. */ staticfinalint MIN_TREEIFY_CAPACITY = 64;
/** * Minimum number of rebinnings per transfer step. Ranges are * subdivided to allow multiple resizer threads. This value * serves as a lower bound to avoid resizers encountering * excessive memory contention. The value should be at least * DEFAULT_CAPACITY. */ privatestaticfinalint MIN_TRANSFER_STRIDE = 16;
/** * The number of bits used for generation stamp in sizeCtl. * Must be at least 6 for 32bit arrays. */ privatestaticint RESIZE_STAMP_BITS = 16;
/** * The maximum number of threads that can help resize. * Must fit in 32 - RESIZE_STAMP_BITS bits. */ privatestaticfinalint MAX_RESIZERS = (1 << (32 - RESIZE_STAMP_BITS)) - 1;
/** * The bit shift for recording size stamp in sizeCtl. */ privatestaticfinalint RESIZE_STAMP_SHIFT = 32 - RESIZE_STAMP_BITS;
/* * Encodings for Node hash fields. See above for explanation. */ staticfinalint MOVED = -1; // hash for forwarding nodes staticfinalint TREEBIN = -2; // hash for roots of trees staticfinalint RESERVED = -3; // hash for transient reservations staticfinalint HASH_BITS = 0x7fffffff; // usable bits of normal node hash
/** Number of CPUS, to place bounds on some sizings */ staticfinalint NCPU = Runtime.getRuntime().availableProcessors();
/** For serialization compatibility. */ privatestaticfinal ObjectStreamField[] serialPersistentFields = { new ObjectStreamField("segments", Segment[].class), new ObjectStreamField("segmentMask", Integer.TYPE), new ObjectStreamField("segmentShift", Integer.TYPE) }; }
publicclassConcurrentHashMap<K,V> extendsAbstractMap<K,V> implementsConcurrentMap<K,V>, Serializable{ /** * The array of bins. Lazily initialized upon first insertion. * Size is always a power of two. Accessed directly by iterators. */ transientvolatile Node<K,V>[] table;
/** * The next table to use; non-null only while resizing. */ privatetransientvolatile Node<K,V>[] nextTable;
/** * Base counter value, used mainly when there is no contention, * but also as a fallback during table initialization * races. Updated via CAS. */ privatetransientvolatilelong baseCount;
/** * Table initialization and resizing control. When negative, the * table is being initialized or resized: -1 for initialization, * else -(1 + the number of active resizing threads). Otherwise, * when table is null, holds the initial table size to use upon * creation, or 0 for default. After initialization, holds the * next element count value upon which to resize the table. */ privatetransientvolatileint sizeCtl;
/** * The next table index (plus one) to split while resizing. */ privatetransientvolatileint transferIndex;
/** * Spinlock (locked via CAS) used when resizing and/or creating CounterCells. */ privatetransientvolatileint cellsBusy;
/** * Table of counter cells. When non-null, size is a power of 2. */ privatetransientvolatile CounterCell[] counterCells;
publicConcurrentHashMap(int initialCapacity, float loadFactor, int concurrencyLevel){ if (!(loadFactor > 0.0f) || initialCapacity < 0 || concurrencyLevel <= 0) thrownew IllegalArgumentException(); if (initialCapacity < concurrencyLevel) // Use at least as many bins initialCapacity = concurrencyLevel; // as estimated threads long size = (long)(1.0 + (long)initialCapacity / loadFactor); int cap = (size >= (long)MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : tableSizeFor((int)size); this.sizeCtl = cap; }
/** * Returns a power of two table size for the given desired capacity. * See Hackers Delight, sec 3.2 */ privatestaticfinalinttableSizeFor(int c){ int n = c - 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; }
/** * Maps the specified key to the specified value in this table. * Neither the key nor the value can be null. */ public V put(K key, V value){ return putVal(key, value, false); }
/** Implementation for put and putIfAbsent */ final V putVal(K key, V value, boolean onlyIfAbsent){ if (key == null || value == null) thrownew NullPointerException(); int hash = spread(key.hashCode()); int binCount = 0; for (Node<K,V>[] tab = table;;) { Node<K,V> f; int n, i, fh; //当table为空时,进行初始化 if (tab == null || (n = tab.length) == 0) tab = initTable(); //若当前散列的位置为空,则直接插入而不用加锁 elseif ((f = tabAt(tab, i = (n - 1) & hash)) == null) { if (casTabAt(tab, i, null, new Node<K,V>(hash, key, value, null))) break; // no lock when adding to empty bin } //若当前散列的位置是table的链接点时,就表明在扩容,调用helpTransfer帮助当前线程扩容 elseif ((fh = f.hash) == MOVED) tab = helpTransfer(tab, f); //散列冲突 else { V oldVal = null; //加锁 synchronized (f) { if (tabAt(tab, i) == f) { //按链表的方式处理 if (fh >= 0) { binCount = 1; for (Node<K,V> e = f;; ++binCount) { K ek; if (e.hash == hash && ((ek = e.key) == key || (ek != null && key.equals(ek)))) { oldVal = e.val; if (!onlyIfAbsent) e.val = value; break; } Node<K,V> pred = e; if ((e = e.next) == null) { pred.next = new Node<K,V>(hash, key, value, null); break; } } } //按红黑树的方式处理 elseif (f instanceof TreeBin) { Node<K,V> p; binCount = 2; if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key, value)) != null) { oldVal = p.val; if (!onlyIfAbsent) p.val = value; } } } } //若链表的长度大于TREEIFY_THRESHOLD,则将链表转换为红黑树 if (binCount != 0) { if (binCount >= TREEIFY_THRESHOLD) treeifyBin(tab, i); if (oldVal != null) return oldVal; break; } } } addCount(1L, binCount); returnnull; }
/** * Returns the value to which the specified key is mapped, * or {@code null} if this map contains no mapping for the key. * * @throws NullPointerException if the specified key is null */ public V get(Object key){ Node<K,V>[] tab; Node<K,V> e, p; int n, eh; K ek; int h = spread(key.hashCode()); if ((tab = table) != null && (n = tab.length) > 0 && (e = tabAt(tab, (n - 1) & h)) != null) { if ((eh = e.hash) == h) { if ((ek = e.key) == key || (ek != null && key.equals(ek))) return e.val; } elseif (eh < 0) return (p = e.find(h, key)) != null ? p.val : null; while ((e = e.next) != null) { if (e.hash == h && ((ek = e.key) == key || (ek != null && key.equals(ek)))) return e.val; } } returnnull; }