2、HashMap線程安全問題
1、併發測試,會出現的賦值成功,但是結果卻是數量少了。
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
map.put("aaa_"+i, "value_aaa_"+i);
System.out.println(Thread.currentThread().getName() + "put");
}
}
},"aaa").start();
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
map.put("bbb_"+i, "value_bbb_"+i);
System.out.println(Thread.currentThread().getName() + "put");
}
}
},"bbb").start();;
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
map.put("ccc_"+i, "value_ccc_"+i);
System.out.println(Thread.currentThread().getName() + "put");
}
}
},"ccc").start();;
Set<Entry<String,Object>> entrySet = map.entrySet(); // 怎麼做到返回所有的映射關係
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
int size = entrySet.size();
System.out.println(size); // 映射的數目纔是hashmap的存放的鍵值對
// 打印結果,會出現size小於3000的情況。
hashmap就是共享資源
分析:
多線程訪問,在創建entry時候,拿到的Entry<K,V> e = table[i] ,那麼再new Entry的時候就會後一個線程覆蓋上一個線程的值。
(原理:多個線程同時發生碰撞的時候,且都在數組的同一個位置時。同時對鏈表的頭部更新操作,出現值被覆蓋)
void createEntry(int hash, K key, V value, int bucketIndex) {
Entry<K,V> e = table[bucketIndex];
table[bucketIndex] = new Entry<>(hash, key, value, e);
size++;
}
2、線程不安全造成環狀鏈表分析
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; // 拿到next,保存舊鏈表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.next (第一次table[i]是null值)
newTable[i] = e; // 再把e賦給newTable[i]
每次循環都是將新來的e指向已經存在的對象newTable[i]處的鏈表,再將此鏈表賦給newTable[i]。這樣做和put原理一樣,複雜度是O(1)。
e = next;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.