ConcurrentHashMap中引入了分段锁的概念,可以理解为将一个大的Map拆分成N个小的Hashtable(通过synchronized保证线程安全),被称为segments,根据key.hashCode来决定把key放到哪个Hashtable中。
对于操作同一segment的两个线程,后一个将被阻塞;对于操作不同segment的两个线程,互不影响--以此相对于Hashtable提高效率。ConcurrentHashMap缺省情况下生成16个segments,也就是允许16个线程并发更新而尽量没有阻塞、锁的争用。
HashMap或者ArrayList边遍历边删除会抛异常,因此需要使用Iterator删除元素;ConcurrentHashMap边遍历边删除或增加操作不会产生影响,即使多个线程一起删除、添加元素也没问题。
一个线程对ConcurrentHashMap增加数据,另外一个线程在遍历时就能获得。
get方法不涉及到锁,即获得对象时没有使用锁;
ConcurrentHashMap允许边遍历边更新,即在使用Iterator进行的遍历的时候,可以使用put、remove方法对Map进行更新,若想获得当前的全部数据,可以使用synchronized将ConcurrentHashMap对象包装,在{}进行Iterator操作;
HashMap或ArrayList在边遍历边删除时会报java.util.ConcurrentModificationException异常,不过可以用迭代器解决;
对ConcurrentHashMap边遍历边删除或者增加操作不会产生异常,遍历的时候都能获得最新值,即使多个线程一起删除、添加也没有问题。
但是,ConcurrentHashMap只保证了原子操作的线程安全:
map.put(key, map.get(key) + 1);
以上操作并非原子操作,包含了三个步骤:
1.map.get
2.+1
3.map.put
其中第1步和第3步,单独来说是线程安全的,可以由ConcurrentHashMap保证;如果map是一个共享对象,线程A执行map.get时,线程B可能在执行map.put,则当线程A执行到map.put时,线程A中的数据已经是脏数据,导致线程不安全;
为了保证线程安全,需要使用同步代码块synchronized(共享变量),之后可以将ConcurrentHashMap换成HashMap,检验ConcurrentHashMap是否还有必要。
转载于:https://www.cnblogs.com/yuanfei1110111/p/10134350.html