关于采用HashMap作为本地缓存遇到的问题
来源:互联网 发布:澳洲留学中介 知乎 编辑:程序博客网 时间:2024/05/10 20:27
最近在做一个的项目,我所要完成的部分是对数据的清洗操作,当收到一条记录时,对记录做相应的适配,然后将适配后的数据返回。做适配就是要与之前的数据进行对比,所以需要对之前的数据做一个缓存,初步考虑用HashMap来进行缓存数据。因为我们的数据量是比较大的,一天大概是2亿条记录,一条记录是36个字段,字段之间用特殊的分隔符隔开。程序中使用了多线程,但是由于我对HashMap操作时,没有使用同步,导致CPU的使用率一直标的很高,并提示温度过高,我很郁闷,不得不将程序停止。事后,同事问我,是否程序中有死循环,其实代码逻辑很简单,连循环都没有,后来通过检查知道HashMap是非线程安全的,在多线程程序一定要注意。下面是对HashMap一些分析:(摘自http://blog.sina.com.cn/s/blog_4a1f59bf0100o98k.html)
public V put(K key, V value) { if (key == null) return putForNullKey(value); int hash = hash(key.hashCode()); int i = indexFor(hash, table.length); 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++; addEntry(hash, key, value, i); return null; }
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); if (size++ >= threshold) resize(2 * table.length); }
从代码中,可以看到,如果发现哈希表的大小超过阀值threshold,就会调用resize方法,扩大容量为原来的两倍,而扩大容量的做法是新建一个 Entry[]:
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); table = newTable; threshold = (int)(newCapacity * loadFactor); }
一般我们声明HashMap时,使用的都是默认的构造方法:HashMap<K,V>,看了代码你会发现,它还有其它的构造方法:HashMap(int initialCapacity, float loadFactor),其中参数initialCapacity为初始容量,loadFactor为加载因子,而之前我们看到的threshold = (int)(capacity * loadFactor); 如果在默认情况下,一个HashMap的容量为16,加载因子为0.75,那么阀值就是12,所以在往HashMap中put的值到达12时,它将自动扩容两倍,如果两个线程同时遇到HashMap的大小达到12的倍数时,就很有可能会出现在将oldTable转移到newTable的过程中遇到问题,从而导致最终的HashMap的值存储异常。
JDK1.0引入了第一个关联的集合类HashTable,它是线程安全的。 HashTable的所有方法都是同步的。
JDK2.0引入了HashMap,它提供了一个不同步的基类和一个同步的包装器synchronizedMap。synchronizedMap被称为有条件的线程安全类。
JDK5.0util.concurrent包中引入对Map线程安全的实现ConcurrentHashMap,比起synchronizedMap,它提供了更高的灵活性。同时进行的读和写操作都可以并发地执行。
所以在开始的测试中,如果我们采用ConcurrentHashMap,它的表现就很稳定,所以以后如果使用Map实现本地缓存,为了提高并发时的稳定性,还是建议使用ConcurrentHashMap。
- 关于采用HashMap作为本地缓存遇到的问题
- 本地缓存的实现以及遇到的问题
- 关于ImageLoader加载本地缓存下来的图片的问题?
- 关于本地通遇到的问题及解决的方法
- 采用JDBC连接池遇到的问题
- 网站采用gb2312编码遇到的问题
- 关于hashmap的遍历问题
- 关于hashmap的遍历问题
- 关于HashMap的拷贝问题
- 关于HashMap的使用问题
- 关于hashmap put 的问题
- 关于HashMap的一些问题
- 使用可变类作为HashMap键值所带来的问题
- 关于Asp.net网站的本地发布和遇到问题的解决方法
- 关于本地缓存登陆 和 域用户将计算机加入域的问题及登录过程- -
- 关于模型数组进行本地保存中遇到的一些问题
- 有关于RTX本地缓存的问题
- AFNetworking 图片的本地缓存问题
- 关于配置到dbca输入密码时提示could not validate asmsnmp password ora-12541:no listener的问题
- 静态监听
- 随机密码
- "vector iterators incompatible"及一些感想
- 在vc++中用Accelerator建立一些快捷键
- 关于采用HashMap作为本地缓存遇到的问题
- Android开发_android权限
- lab1 MAC的竞争窗口
- 【Cocos2d-X开发学习笔记】第04期:渲染框架之场景类(CCScene)的使用
- Linux学习-查看目录和文件
- Android开发_Activity打成jar包
- 再叙,觉醒即是转机,思变为时不晚
- HDU 2594 Simpsons’ Hidden Talents KMP
- JSP(1)之web开发基础、JSP语法及内置对象