HashMap的fast-fail和ConcurrentHashMap的fail-safe实例
声明:迁移自本人CSDN博客https://blog.csdn.net/u013365635
Java HashMap遍历过程中如果元素被修改会导致遍历失败,ConcurrentHashMap则不会有这个问题。由此引出HashMap的fast-fail机制和ConcurrentHashMap的的fail-safe机制。
看如下实例。
首先看HashMap的fast-fail
package com;
import java.util.HashMap;
import java.util.Map;
public class TestHashMapFastFail
{
public static void main(String[] args)
{
System.out.println("test HashMap fast-fail");
Map<Integer, String> testHashMap = new HashMap<Integer, String>();
testHashMap.put(1000, "1000");
testHashMap.put(2000, "2000");
testHashMap.put(3000, "3000");
testHashMap.put(4000, "4000");
testHashMap.put(5000, "5000");
System.out.println(testHashMap.size());
for (Map.Entry<Integer, String> entry : testHashMap.entrySet())
{
int key = entry.getKey();
System.out.println("key=" + key);
if (key == 3000)
{
testHashMap.remove(key);
}
}
System.out.println(testHashMap.size());
for (Map.Entry<Integer, String> entry : testHashMap.entrySet())
{
System.out.println(entry.getKey() + "-->" + entry.getValue());
}
}
}
运行结果
test HashMap
5
key=2000
key=4000
key=1000
key=3000
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextNode(HashMap.java:1437)
at java.util.HashMap$EntryIterator.next(HashMap.java:1471)
at java.util.HashMap$EntryIterator.next(HashMap.java:1469)
at com.TestHashMapFastFail.main(TestHashMapFastFail.java:18)
可以看到执行remove操作后,下一轮迭代立刻失效,并抛出异常,这就是所谓的fast-fail。
再看ConcurrentHashMap的fail-safe
package com;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class TestConcurrentHashMapFailSafe
{
public static void main(String[] args)
{
System.out.println("test ConcurrentHashMap fast-fail");
Map<Integer, String> testConcurrentHashMap = new ConcurrentHashMap<Integer, String>();
testConcurrentHashMap.put(100, "100");
testConcurrentHashMap.put(200, "200");
testConcurrentHashMap.put(300, "300");
testConcurrentHashMap.put(400, "400");
testConcurrentHashMap.put(500, "500");
System.out.println(testConcurrentHashMap.size());
for (Map.Entry<Integer, String> entry : testConcurrentHashMap.entrySet())
{
int key = entry.getKey();
System.out.println("key=" + key);
if (key == 300)
{
testConcurrentHashMap.remove(key);
}
}
System.out.println(testConcurrentHashMap.size());
for (Map.Entry<Integer, String> entry : testConcurrentHashMap.entrySet())
{
System.out.println(entry.getKey() + "-->" + entry.getValue());
}
}
}
运行结果
test ConcurrentHashMap fast-fail
5
key=400
key=100
key=500
key=200
key=300
3
100-->100
500-->500
300-->300
可以看出,尽管在迭代过程中执行了remove操作,但是ConcurrentHashMap对外的表现仍然正常,这就是所谓的fail-safe。原因在于ConcurrentHashMap返回的迭代器是弱一致性,ConcurrentHashMap底层数据结构改变时并且不会抛出ConcurrentModificationException异常。
所以,这也是选择ConcurrentHashMap可以获得的一个额外好处,或者说是解决HashMap fast-fail的一种方法,还有一个方法就是使用迭代器的remove方法而不是使用集合的remove方法,示例如下。
package com;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class TestHashMapFastFail2
{
public static void main(String[] args)
{
System.out.println("test solve HashMap fast-fail");
Map<Integer, String> testHashMap = new HashMap<Integer, String>();
testHashMap.put(1000, "1000");
testHashMap.put(2000, "2000");
testHashMap.put(3000, "3000");
testHashMap.put(4000, "4000");
testHashMap.put(5000, "5000");
System.out.println(testHashMap.size());
Iterator iterator = testHashMap.entrySet().iterator();
while (iterator.hasNext())
{
int key = (int)((Map.Entry)iterator.next()).getKey();
System.out.println("key=" + key);
if (key == 2000 || key == 4000)
{
iterator.remove();
}
}
System.out.println(testHashMap.size());
for (Map.Entry<Integer, String> entry : testHashMap.entrySet())
{
System.out.println(entry.getKey() + "-->" + entry.getValue());
}
}
}
运行结果
test solve HashMap fast-fail
5
key=2000
key=4000
key=1000
key=3000
key=5000
3
1000-->1000
3000-->3000
5000-->5000
集合的 fast-fail 问题是初学者很容易犯的错误。
说说fast-fail机制和fail-safe机制设计的原因。有人可能会问,既然fast-fail有这么多弊端,为什么还要设计呢,以HashMap为例,因为HashMap本身就是设计成线程不安全的,不支持多个线程同时安全修改,但这也意味着HashMap有较快的速度。fail-safe机制设计的初衷就是保证多线程并发安全地修改集合或Map类。当然,本文的用例都是单线程中的修改操作,主要是为了引出这2个概念。至于内部实现机制,看源码吧。
HashMap的fast-fail和ConcurrentHashMap的fail-safe实例的更多相关文章
- HashMap底层原理以及与ConCurrentHashMap区别
HashMap基于hashing原理,我们通过put()和get()方法储存和获取对象.当我们将键值对传递给put()方法时,它调用键对象的hashCode()方法来计算hashcode,让后找到bu ...
- HashMap不安全后果及ConcurrentHashMap线程安全原理
Java集合HashMap不安全后果及ConcurrentHashMap 原理 目录 HashMap JDK7 HashMap链表循环造成死循环 HashMap数据丢失 JDK7 Concurrent ...
- HashMap、Hash Table、ConcurrentHashMap
这个这个...本王最近由于开始找实习工作了,所以就在牛客网上刷一些公司的面试题,大多都是一些java,前端HTML,js,jquery,以及一些好久没有碰的算法题,说实话,有点难受,其实在我不知道的很 ...
- 非线程安全的HashMap 和 线程安全的ConcurrentHashMap
在平时开发中,我们经常采用HashMap来作为本地缓存的一种实现方式,将一些如系统变量等数据量比较少的参数保存在HashMap中,并将其作为单例类的一个属性.在系统运行中,使用到这些缓存数据,都可以直 ...
- 020-并发编程-java.util.concurrent之-jdk6/7/8中ConcurrentHashMap、HashMap分析
一.概述 哈希表(hash table)也叫散列表,是一种非常重要的数据结构,应用场景及其丰富,许多缓存技术(比如memcached)的核心其实就是在内存中维护一张大的哈希表. 是根据关键码值(Key ...
- BZOJ 2434: [Noi2011]阿狸的打字机 [AC自动机 Fail树 树状数组 DFS序]
2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 2545 Solved: 1419[Submit][Sta ...
- BZOJ 3172: [Tjoi2013]单词 [AC自动机 Fail树]
3172: [Tjoi2013]单词 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 3198 Solved: 1532[Submit][Status ...
- fail树
前置技能:AC自动机 假设我们有了一个AC自动机,然后在上面进行字符串匹配. 上面是一个有四个字符串的AC自动机(abcde.aacdf.cdf.cde),虚线是fail指针,实线是转移. 这是上一次 ...
- 【BZOJ 2434】【NOI 2011】阿狸的打字机 fail树
完全不会啊,看题解还看了好久,我是蒟蒻$QAQ$ $zyf$的题解挺好的:http://blog.csdn.net/clove_unique/article/details/51059425 $fai ...
- BZOJ2434 [Noi2011]阿狸的打字机(AC自动机 + fail树 + DFS序 + 线段树)
题目这么说的: 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母.经阿狸研究发现,这个打字机是这样工作的: 输入小 ...
随机推荐
- 数据库连接需要dll
连接oracle引用: Oracle.ManagedDataAccess.dll和Oracle.ManagedDataAccess.EntityFramework.dll, 连接sqlserver 连 ...
- Window Server 2019 配置篇(5)- 在域中建立WSUS以实现自动更新
上次讲到我们的服务器群中增加了一台用于自动部署的服务器,这次我们要添加一台搭载WSUS服务的服务器,以实现对window更新的管理 那么WSUS是什么服务呢? WSUS是window server u ...
- Kafka--生产者
一个应用程序在很多情况下需要往Kafka写入消息:记录用户的活动(用于审计和分析),记录度量指标,保存日志消息,记录智能家电的信息,与其他应用程序进行异步通信,缓冲即将写入到数据库的数据,等等. 多样 ...
- matlab和fortran混合编程
matlab2016b+vs2010+ivf2013+f90 其实默认是f77语法,但通过配置可以改变为自由格式. 默认只能f77代码,怎样修改: https://ww2.mathworks.cn/m ...
- 052-PHP输出多个参数
<?php $x=5; //初始化两个变量 $y=10; echo $x,$y,"<br />$x+$y=",$x+$y; //输出多个参数 ?>
- [APIO2012]派遣 可并堆
Background 在一个忍者的帮派里,一些忍者们被选中派遣给顾客,然后依据自己的工作获取报偿. Description 在这个帮派里,有一名忍者被称之为Master.除了Master以外,每名忍者 ...
- Assignment写作谨慎学术抄袭是关键
学术写作(Academic Writing)作为留学生涯的“必修课”,总是让闻者叹气,抓耳挠腮.初入课堂的留学生,更是缺乏写作经验不知从何下笔,只想仰天长啸“Essay真的好难啊!!”面对一个Essa ...
- Spark 内存管理
Spark 内存管理 Spark 执行应用程序时, 会启动 Driver 和 Executor 两种 JVM 进程 Driver 负责创建 SparkContext 上下文, 提交任务, task的分 ...
- MongoDB Limit
版权所有,未经许可,禁止转载 章节 MongoDB 入门 MongoDB 优势 MongoDB 安装 MongoDB 数据建模 MongoDB 创建数据库 MongoDB 删除数据库 MongoDB ...
- inkscape批量将svg转为pdf
for i in *.svg;do inkscape --export-pdf=${i%.*}.pdf $i;done