【面试库】--HashMap多线程put后get null ,get 死循环,get数据丢失(167)
来源:互联网 发布:女程序员标准装扮 编辑:程序博客网 时间:2024/05/20 22:02
0 公共put源码
public V put(K key, V value){ ...... //算Hash值 int hash = hash(key.hashCode()); int i = indexFor(hash, table.length); //如果该key已被插入,则替换掉旧的value (链接操作) 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不存在,需要增加一个结点 addEntry(hash, key, value, i); return null ;}
1 put非null元素后get出来的却是null
源码定位
void transfer(Entry[] newTable) { Entry[] src = table; int newCapacity = newTable.length; for ( int j = 0 ; j < src.length; j++) { Entry e = src[j]; if (e != null ) { src[j] = null ;//将table[j]设置为null,并发访问到 原table返回的就是null do { Entry next = e.next; int i = indexFor(e.hash, newCapacity); e.next = newTable[i]; newTable[i] = e; e = next; } while (e != null ); } }}
分析: 线程1 将table【j】=null;线程2同时去访问原table,结果违反了直觉
2 多线程put后可能导致get死循环
源码定位
void resize( int newCapacity){ Entry[] oldTable = table; int oldCapacity = oldTable.length; ...... //创建一个新的Hash Table Entry[] newTable = new Entry[newCapacity]; //将Old Hash Table上的数据迁移到New Hash Table上 transfer(newTable);//还是这里!! table = newTable; threshold = ( int )(newCapacity * loadFactor);}void transfer(Entry[] newTable){ Entry[] src = table; int newCapacity = newTable.length; // 头插法:从OldTable里摘一个元素出来,然后放到NewTable中 for ( int j = 0 ; j < src.length; j++) { Entry<K,V> e = src[j]; if (e != null ) { src[j] = null ; do { Entry<K,V> next = e.next;//如果此处 线程1 时间片用完,而 线程2 得到调度并将循环执行完,再轮到线程1 调度时问题来了!链表翻转了。 int i = indexFor(e.hash, newCapacity); e.next = newTable[i]; newTable[i] = e; e = next; } while (e != null ); } }}
分析:
注释出–>如果此处 线程1 时间片用完hang起,而 线程2 得到调度并将循环执行完,再轮到线程1 调度时问题来了!链表翻转了。线程1再次执行transfer重现转移时,由于线程2完成导致链表出现翻转,使得线程1最终构造了一个循环链表,当进行get时,cpu利用100%.参考:
https://my.oschina.net/u/2394328/blog/661626
多线程put的时候可能导致元素丢失
源码定位
void addEntry( int hash, K key, V value, int bucketIndex){ Entry<K,V> e = table[bucketIndex]; table[bucketIndex] = new Entry<K,V>(hash, key, value, e);//这里线程1和线程2同时获取e,执行后必然有一个丢失 if (size++ >= threshold) resize( 2 * table.length);}
分析:主要问题出在addEntry方法的new Entry (hash, key, value, e),如果两个线程都同时取得了e,则他们下一个元素都是e,然后赋值给table元素的时候有一个成功有一个丢失。
0 0
- 【面试库】--HashMap多线程put后get null ,get 死循环,get数据丢失(167)
- 多线程put后可能导致get死循环
- HashMap put() get()
- HashMap.put/get方法
- hashmap陷入get方法陷入死循环
- HashMap中put与get的实现
- HashMap原理分析put get remove
- HashMap的put和get方法原理
- 手写HashMap,实现put,get以及扩容
- hashmap的数据结构以及put和get
- hashMap底层put和get方法逻辑
- HashMap底层详解-001-数据结构、put、get
- HashMap的put,get方法实现!
- GET/POST/PUT/DELETE
- SICP chapter2 put get
- get/post/put/delete
- curl GET/PUT examples
- jdk1.8 hashmap多线程put不会造成死循环
- 源码阅读--RxJava(三)
- 图灵机停机问题的不可判定性
- 函数书写方式
- Ubuntu安装chrome
- (转)Android开发-Activity中finish() onDestroy() 和System.exit()的区别
- 【面试库】--HashMap多线程put后get null ,get 死循环,get数据丢失(167)
- leetcodeOJ 90. Subsets II
- @Repository、@Service、@Controller 和 @Component(转载)
- Android MD5加密工具类
- AOJ 842 西瓜的编译原理【字典树】
- Android安全输入设计与思考
- 接口文档
- 了解BitSet类并实现素数筛选--Eratosthenes筛选法
- Dom4JUtils工具类(查找对象,回写操作)