1. hashMap中扩容
transfer时可能出现循环链表问题
1. 使用头插法
hashMap是并发不安全的,hashTable是并发安全,使用synchronized保证线程安全。
hashTable保证线程安全的put方法实例:
public synchronized V put(K key, V value) {
void addEntry(int hash, K key, V value, int bucketIndex) {
//如果hashMap大小大于等于阈值并且数据元素不为空扩容
if ((size >= threshold) && (null != table[bucketIndex])) {
resize(2 * table.length);
hash = (null != key) ? hash(key) : 0;
bucketIndex = indexFor(hash, table.length);//计算数组下标位置
}
createEntry(hash, key, value, bucketIndex);
}
//扩容
void resize(int newCapacity) {
Entry[] oldTable = table;
int oldCapacity = oldTable.length;
if (oldCapacity == MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return;
}
Entry[] newTable = new Entry[newCapacity];
//将老数组元素放入新数组
transfer(newTable, initHashSeedAsNeeded(newCapacity));
table = newTable;
threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);
}
//转移老数组元素,双重循环遍历数组和链表
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;
}
}
}
1.1 get() (TODO)
1.2 remove问题
remove最后一个时报错:Exception in thread "main"java.util.ConcurrentModificationException
解决方法:调用迭代器的remove方法
错误发生原因:调用map.remove(key)方法时modCount会++于是在调用hashmap的nextEntry()时报错。
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
而解决方法使用迭代器remove方法时hashmap会重新赋值
expectedModCount = modCount;
import java.util.HashMap;
import java.util.Iterator;
public class HashMapTest {
public static void main(String[] args) {
HashMap<String, String> map = new HashMap<>();
map.put("1","1");
map.put("2","2");
// for(String key:map.keySet()){
// if("1".equals(key)){
// map.remove(key);
// }
// }
// for(String key:map.keySet()){
// if(key.equals("2")){
// map.remove(key);//Exception in thread "main" java.util.ConcurrentModificationException
// }
// }
//上述代码编译后代码
Iterator i$ = map.keySet().iterator();
while(i$.hasNext()) {
String key = (String)i$.next();
if (key.equals("2")) {
// map.remove(key);//Exception in thread "main" java.util.ConcurrentModificationException
//解决方法调用iterator的remove方法
i$.remove();
}
}
}
}
2. jdk7-cocurrentHashMap
cocurrentHashMap采用分段思想,segment,里面会有一个一个的hashEntry数组组成,segment继承reentrantLock,所以只能保证线程安全的。
2.1 构造方法
DEFAULT_INITIAL_CAPACITY:默认初始大小16 DEFAULT_LOAD_FACTOR:0.75f,作为一个计算系数吧! DEFAULT_CONCURRENCY_LEVEL:并发级别,默认16 public ConcurrentHashMap() { this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL); }
public ConcurrentHashMap(int initialCapacity,
float loadFactor, int concurrencyLevel) {
if (!(loadFactor > 0) || initialCapacity < 0 || concurrencyLevel <= 0)
throw new IllegalArgumentException();
if (concurrencyLevel > MAX_SEGMENTS)
concurrencyLevel = MAX_SEGMENTS;
// Find power-of-two sizes best matching arguments
int sshift = 0;
int ssize = 1;
while (ssize < concurrencyLevel) {
++sshift;
ssize <<= 1;
}
this.segmentShift = 32 - sshift;
this.segmentMask = ssize - 1;
if (initialCapacity > MAXIMUM_CAPACITY)
initialCapacity = MAXIMUM_CAPACITY;
int c = initialCapacity / ssize;
if (c * ssize < initialCapacity)
++c;
int cap = MIN_SEGMENT_TABLE_CAPACITY;
while (cap < c)
cap <<= 1;
// create segments and segments[0]
Segment<K,V> s0 =
new Segment<K,V>(loadFactor, (int)(cap * loadFactor),
(HashEntry<K,V>[])new HashEntry[cap]);
Segment<K,V>[] ss = (Segment<K,V>[])new Segment[ssize];
UNSAFE.putOrderedObject(ss, SBASE, s0); // ordered write of segments[0]
this.segments = ss;
}
2.2 put方法
public V put(K key, V value) {
Segment<K,V> s;
if (value == null)
throw new NullPointerException();
int hash = hash(key);
int j = (hash >>> segmentShift) & segmentMask;
if ((s = (Segment<K,V>)UNSAFE.getObject // nonvolatile; recheck
(segments, (j << SSHIFT) + SBASE)) == null) // in ensureSegment
s = ensureSegment(j);
return s.put(key, hash, value, false);
}