Java Maps
HashMap
是线程不安全的,主要对于写操作来说,两个以上线程同时写入Map会被互相覆盖。线程安全指的保证对同一个map的写入操作按照顺序进行,一次只能一个线程更改。比如向HashMap里put(key, value1)有可能key对应的是其他线程同时写入的value2
HashMap的遍历有两种常用的方法,那就是使用keyset及entryset来进行遍历,但两者的遍历速度是有差别的.
第一种:
// 效率高,以后一定要使用此种方式!
Map map = new HashMap(); Iterator iter = map.entrySet().iterator(); while (iter.hasNext()) { Map.Entry entry = (Map.Entry) iter.next(); Object key = entry.getKey(); Object val = entry.getValue(); }
第二种:
// 效率低,以后尽量少使用!
Map map = new HashMap(); Iterator iter = map.keySet().iterator(); while (iter.hasNext()) { Object key = iter.next(); Object val = map.get(key); }
HashMap或者ArrayList边遍历边删除数据会报java.util.ConcurrentModificationException异常,需要用Iterator遍历删除。ConcurrentHashMap没有这种问题。
public void test() { Map bb = new HashMap(); bb.put("1", "wj"); bb.put("2", "ry"); Iterator it = bb.keySet().iterator(); while(it.hasNext()) { Object ele = it.next(); #bb.remove(ele); //wrong it.remove(ele); //right
} System.out.println("Success!");
}
对于ArrayList,不要在 foreach 循环里进行元素的 remove/add 操作。remove 元素请使用 Iterator 方式,如果并发操作,需要对 Iterator 对象加锁。
//Right Iterator<String> it = a.iterator(); while(it.hasNext()){ String temp = it.next(); if(删除元素的条件){ it.remove(); } }
//Wrong List<String> a = new ArrayList<String>(); a.add("1"); a.add("2"); for (String temp : a) { if("1".equals(temp)){ a.remove(temp); } }
ConcurrentHashMap
public V get(Object key)不涉及到锁,也就是说获得对象时没有使用锁,保证读到最新的值
put、remove方法要使用锁,但并不一定有锁争用,原因在于ConcurrentHashMap将缓存的变量分到多个Segment,每个Segment上有一个锁,只要多个线程访问的不是一个Segment就没有锁争用,就没有堵塞,各线程用各自的锁,ConcurrentHashMap缺省情况下生成16个Segment,也就是允许16个线程并发的更新而尽量没有锁争用;
Iterator对象的使用,不一定是和其它更新线程同步,获得的对象可能是更新前的对象,ConcurrentHashMap允许一边更新、一边遍历,也就是说在Iterator对象遍历的时候,ConcurrentHashMap也可以进行remove,put操作,且遍历的数据会随着remove,put操作产出变化,所以希望遍历到当前全部数据的话,要么以ConcurrentHashMap变量为锁进行同步(synchronized该变量),要么使用CopiedIterator包装iterator,使其拷贝当前集合的全部数据,但是这样生成的iterator不可以进行remove操作。
ConcurrentHashMap is much quicker than SynchronizedHashMap. ConcurrentHashMap所使用的锁分段技术,首先将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问。
对ConcurrentHashMap边遍历边删除或者增加操作不会产生异常(可以不用迭代方式删除元素),因为其内部已经做了维护,遍历的时候都能获得最新的值。即便是多个线程一起删除、添加元素也没问题。
ConcurrentHashMap或者说所有的Map都不保证非原子性的操作,比如判断contains后再get的值可能已经改变,需要对整个Map加锁
You should use ConcurrentHashMap when you need very high concurrency in your project.
It is thread safe without synchronizing the whole map.
Reads can happen very fast while write is done with a lock.
There is no locking at the object level.
The locking is at a much finer granularity at a hashmap bucket level.
ConcurrentHashMap doesn’t throw a ConcurrentModificationException if one thread tries to modify it while another is iterating over it.
ConcurrentHashMap uses multitude of locks
HashTable
线程安全,但是对整个Map上锁,读和写都需要同步,在高竞争环境下效率很低,有Scalability 的问题
HashMap
Note that this implementation is not synchronized. If multiple threads access a hashmap concurrently, and at least one of the threads modifies the map structurally, it must be synchronized externally. (A structural modification is any operation that adds or deletes one or more mappings; merely changing the value associated with a key that an instance already contains is not a structural modification.) This is typically accomplished by synchronizing on some object that naturally encapsulates the map. If no such object exists, the map should be "wrapped" using the Collections.synchronizedMap method. This is best done at creation time, to prevent accidental unsynchronized access to the map
SynchronizedHashMap
Synchronization at Object level.
Every read/write operation needs to acquire lock.
Locking the entire collection is a performance overhead.
This essentially gives access to only one thread to the entire map & blocks all the other threads.
It may cause contention.
SynchronizedHashMap returns Iterator, which fails-fast on concurrent modification.
集合类 |
Key |
Value |
Super |
说明 |
Hashtable |
不允许为 null |
不允许为 null |
Dictionary |
线程安全 |
ConcurrentHashMap |
不允许为 null |
不允许为 null |
AbstractMap |
线程局部安全 |
TreeMap |
不允许为 null |
允许为 null |
AbstractMap |
线程不安全 |
HashMap |
允许为 null |
允许为 null |
AbstractMap |
线程不安全 |
Java Maps的更多相关文章
- Java Maps的9个常见问题
一般来说,Map是一种由键值对组成的数据结构,其中键(key)在Map中是不能重复的: 本篇文章总结了9个最常见的问题(关于Java Map及其实现类): 出于简单考虑,在代码例子中我将不使用泛型,因 ...
- Java开发者常犯的十个错误
翻译自:Top 10 Mistakes Java Developers Make 文章列出了Java开发者最常犯的是个错误. 1.将数组转换为ArrayList 为了将数组转换为ArrayList,开 ...
- Top 10 Mistakes Java Developers Make(转)
文章列出了Java开发者最常犯的是个错误. 1.将数组转换为ArrayList 为了将数组转换为ArrayList,开发者经常会这样做: ? 1 List<String> list = A ...
- Java 学习(21):Java 实例
Java 实例 本章节我们将为大家介绍 Java 常用的实例,通过实例学习我们可以更快的掌握 Java 的应用. Java 环境设置实例 //HelloWorld.java 文件 public cla ...
- python调用Java方法传入HashMap ArrayList
1.Java代码: package com; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap ...
- jackson官方快速入门文档
官方地址: http://jackson.codehaus.org/ http://wiki.fasterxml.com/JacksonInFiveMinutes http://wiki.faster ...
- Caching Best Practices--reference
reference:http://java.dzone.com/articles/caching-best-practices There is an irresistible attraction ...
- Jackson - Quickstart
JSON Three Ways Jackson offers three alternative methods (one with two variants) for processing JSON ...
- Scala入门指南与建议
最近在学习使用Scala语言做项目,感觉这门语言实在是太优美了!作为一个本科数学.研究生机器学习专业的混合人才(哈哈),这门语言真的是满足了普通计算机编程(告诉计算机怎么做)和函数式编程(告诉计算机做 ...
随机推荐
- Activity间传递数据
1.从当前的Activity传递数据到下一个Activity: (1)发送方(当前的Activity): Bundle bundle = new Bundle(); bundle.putString ...
- MySQL存储过程--带参数报错1064
DELIMITER $$ USE `student`$$ DROP PROCEDURE IF EXISTS `sync_student`$$ CREATE DEFINER=`student`@`%` ...
- TypeScript入门-函数
▓▓▓▓▓▓ 大致介绍 TypeScript为JavaScript函数添加了额外的功能,让我们可以更容易地使用.TypeScript中的函数也包括JavaScript中最常见的两种函数 functio ...
- AngularJS1.X学习笔记14-动画(解读文档)
最近在看算法分析,那个大O啊,小o啊,分治法啊(目前就看到这里),真是搞死了.这回呢休息一下,学学AngularJS动画,上一篇文章根据自由男人的书简单谈到了动画的话题,发现反响很大(好吧,我说慌了, ...
- IntelliJ IDEA应用[一]下载与安装
一.IntelliJ IDEA 12.1.6的下载 IntelliJ IDEA的官方下载网站:http://www.jetbrains.com/idea/download/
- 热爱H5
我不去想是否能够功成名就既然选择了前端便只顾埋头于无声 我不去想能否赢得掌声既然钟情于IT就勇敢得踏步前行 我不去想前行的路上会不会日暮穷途既然目标是未来留给现在的只能是汗水 我不去想所谓的成功是不是 ...
- python——网络编程
Socket socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求. sock ...
- bootstrap快速入门笔记(九)-响应式工具
一,可用的类 超小屏幕手机 (<768px) 小屏幕平板 (≥768px) 中等屏幕桌面 (≥992px) 大屏幕桌面 (≥1200px) .visible-xs-* 可见 隐藏 隐藏 隐藏 ...
- (函数封装)domReady
一般的我们用window.onload()来判断文档是否加载完成,我们一般采用下面的做法: 当文档加载全部完后,我们在执行代码块(很显然,当需要加载的文档及节点庞大时,用户体验可能会变很差) wind ...
- 分布式锁与实现(二)——基于ZooKeeper实现
引言 ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件.它是一个为分布式应用提供一致性服务的软件,提 ...