摘要:并发的为什么会引起死循环在多线程使用场景中,应该尽量避免使用线程不安全的,而使用线程安全的。那么为什么说是线程不安全的,下面举例子说明在并发的多线程使用场景中使用可能造成死循环。注意此时两个线程已经成功添加数据。
并发的HashMap为什么会引起死循环?
在多线程使用场景中,应该尽量避免使用线程不安全的 HashMap,而使用线程安全的 ConcurrentHashMap。那么为什么说 HashMap 是线程不安全的,下面举例子说明在并发的多线程使用场景中使用 HashMap 可能造成死循环。代码例子如下(便于理解,仍然使用 JDK1.7 的环境):
public class HashMapInfiniteLoop { private static HashMapmap = new HashMap (2,0.75f); public static void main(String[] args) { map.put(5, "C"); new Thread("Thread1") { public void run() { map.put(7, "B"); System.out.println(map); }; }.start(); new Thread("Thread2") { public void run() { map.put(3, "A); System.out.println(map); }; }.start(); } }
其中,map初始化为一个长度为2的数组,loadFactor=0.75,threshold=2*0.75=1,也就是说当put第二个key的时候,map就需要进行resize。
通过设置断点让线程1和线程2同时debug到transfer方法(3.3小节代码块)的首行。注意此时两个线程已经成功添加数据。放开thread1的断点至transfer方法的“Entry next = e.next;” 这一行;然后放开线程2的的断点,让线程2进行resize。结果如下图。
注意,Thread1的 e 指向了key(3),而next指向了key(7),其在线程二rehash后,指向了线程二重组后的链表。
线程一被调度回来执行,先是执行 newTalbe[i] = e, 然后是e = next,导致了e指向了key(7),而下一次循环的next = e.next导致了next指向了key(3)。
e.next = newTable[i] 导致 key(3).next 指向了 key(7)。注意:此时的key(7).next 已经指向了key(3), 环形链表就这样出现了。
于是,当我们用线程一调用map.get(11)时,悲剧就出现了——Infinite Loop。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/74393.html
摘要:关于不安全的问题,感兴趣的可以去看一下这篇文章老生常谈,的死循环。 废话不多说,直接进入主题: 首先我们从构造方法开始: public HashMap() { this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR); } public HashMap(int initialCapacity, f...
摘要:今天在复制代码时,遇到死循环,导致在里面执行没有反应其中第二个循环是直接粘贴的,其中的忘记修改,正确的代码是后续应该避免犯这个错误 今天在复制代码时,遇到死循环,导致在 Console 里面执行没有反应: var s = [] var newA = unique(a) var newB = unique(b) for (var i = 0; i < ne...
摘要:开发时,我们经常会使用或等钩子,以便在更新文章或分类时,增加一些附加数据,这些钩子触发的时机是发布或更新数据的时间,如果处理不好,就会出现死循环的情况,导致更新数据时出现死循环的情况。我们可以做的是在开发过程中尽量小心,避免死循环的出现。 WordPress 开发时,我们经常会使用 save_post 或 create_post_tag 等钩子,以便在更新文章或分类时,增加一些附加数据...
阅读 1312·2021-11-22 09:34
阅读 2509·2021-11-12 10:36
阅读 1057·2021-11-11 16:55
阅读 2277·2020-06-22 14:43
阅读 1422·2019-08-30 15:55
阅读 1924·2019-08-30 15:53
阅读 1723·2019-08-30 10:50
阅读 1190·2019-08-29 12:15