ConcurrentHashMap使用要点
ConcurrentHashMap的简要总结:
1、public V get(Object key)不涉及到锁,也就是说获得对象时没有使用锁;
2、put、remove方法要使用锁,但并不一定有锁争用,原因在于ConcurrentHashMap将缓存的变量分到多个Segment,每个Segment上有一个锁,只要多个线程访问的不是一个Segment就没有锁争用,就没有堵塞,各线程用各自的锁,ConcurrentHashMap缺省情况下生成16个Segment,也就是允许16个线程并发的更新而尽量没有锁争用;
3、Iterator对象的使用,不一定是和其它更新线程同步,获得的对象可能是更新前的对象,ConcurrentHashMap允许一边更新、一边遍历,也就是说在Iterator对象遍历的时候,ConcurrentHashMap也可以进行remove,put操作,且遍历的数据会随着remove,put操作产出变化,所以希望遍历到当前全部数据的话,要么以ConcurrentHashMap变量为锁进行同步(synchronized该变量),要么使用CopiedIterator包装iterator,使其拷贝当前集合的全部数据,但是这样生成的iterator不可以进行remove操作。
Hashtable和ConcurrentHashMap的不同点:
1、Hashtable对get,put,remove都使用了同步操作,它的同步级别是正对Hashtable来进行同步的,也就是说如果有线程正在遍历集合,其他的线程就暂时不能使用该集合了,这样无疑就很容易对性能和吞吐量造成影响,从而形成单点。而ConcurrentHashMap则不同,它只对put,remove操作使用了同步操作,get操作并不影响,详情请看以上第1,2点,当前ConcurrentHashMap这样的做法对一些线程要求很严格的程序来说,还是有所欠缺的,对应这样的程序来说,如果不考虑性能和吞吐量问题的话,个人觉得使用Hashtable还是比较合适的;
2、Hashtable在使用iterator遍历的时候,如果其他线程,包括本线程对Hashtable进行了put,remove等更新操作的话,就会抛出ConcurrentModificationException异常,但如果使用ConcurrentHashMap的话,就不用考虑这方面的问题了,详情请看以上第3点;
1.HashMap或者ArrayList边遍历边删除数据会报java.util.ConcurrentModificationException异常
Map<Long, String> mReqPacket = new HashMap<Long, String>();
for (long i = 0; i < 15; i++) {
mReqPacket.put(i, i + "");
} for (Entry<Long, String> entry : mReqPacket.entrySet()) {
long key = entry.getKey();
String value = entry.getValue();
if (key < 10) {
mReqPacket.remove(key);
}
} for (Entry<Long, String> entry : mReqPacket.entrySet()) {
System.out.println(entry.getKey() + " " + entry.getValue());
}
所以要用迭代器删除元素:
Map<Long, String> mReqPacket = new HashMap<Long, String>();
for (long i = 0; i < 15; i++) {
mReqPacket.put(i, i + "");
} for (Iterator<Entry<Long, String>> iterator = mReqPacket.entrySet().iterator(); iterator.hasNext();) {
Entry<Long, String> entry = iterator.next();
long key = entry.getKey();
if (key < 10) {
iterator.remove();
}
} for (Entry<Long, String> entry : mReqPacket.entrySet()) {
System.out.println(entry.getKey() + " " + entry.getValue());
}
2.对ConcurrentHashMap边遍历边删除或者增加操作不会产生异常(可以不用迭代方式删除元素),因为其内部已经做了维护,遍历的时候都能获得最新的值。即便是多个线程一起删除、添加元素也没问题。
Map<Long, String> conMap = new ConcurrentHashMap<Long, String>();
for (long i = 0; i < 15; i++) {
conMap.put(i, i + "");
} for (Entry<Long, String> entry : conMap.entrySet()) {
long key = entry.getKey();
if (key < 10) {
conMap.remove(key);
}
} for (Entry<Long, String> entry : conMap.entrySet()) {
System.out.println(entry.getKey() + " " + entry.getValue());
}
3.一个线程对ConcurrentHashMap增加数据,另外一个线程在遍历时就能获得。
static Map<Long, String> conMap = new ConcurrentHashMap<Long, String>();
public static void main(String[] args) throws InterruptedException {
for (long i = 0; i < 5; i++) {
conMap.put(i, i + "");
}
Thread thread = new Thread(new Runnable() {
public void run() {
conMap.put(100l, "100");
System.out.println("ADD:" + 100);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
Thread thread2 = new Thread(new Runnable() {
public void run() {
for (Iterator<Entry<Long, String>> iterator = conMap.entrySet().iterator(); iterator.hasNext();) {
Entry<Long, String> entry = iterator.next();
System.out.println(entry.getKey() + " - " + entry.getValue());
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
thread.start();
thread2.start();
Thread.sleep(3000);
System.out.println("--------");
for (Entry<Long, String> entry : conMap.entrySet()) {
System.out.println(entry.getKey() + " " + entry.getValue());
}
}
输出:
ADD:100
0 - 0
100 - 100
2 - 2
1 - 1
3 - 3
4 - 4
--------
0 0
100 100
2 2
1 1
3 3
4 4
ConcurrentHashMap使用要点的更多相关文章
- HashMap HashTable和ConcurrentHashMap的区别
HashMap和Hashtable都实现了Map接口,其主要的区别有:线程安全性,同步(synchronization),以及效率. HashMap和Hashtable基本上没啥区别,除了HashMa ...
- 集合03_Map
Map集合总览 保存映射关系key-value键值对,键唯一,值可以重复,Map和Set的实现类相似 Entry是Map的内部类 Map接口中常用的方法: void clear() Set keySe ...
- Java 8 中 ConcurrentHashMap工作原理的要点分析
简介: 本文主要介绍Java8中的并发容器ConcurrentHashMap的工作原理,和其它文章不同的是,本文重点分析了对不同线程的各类并发操作如get,put,remove之间是如何同步的,以及这 ...
- Java8 中 ConcurrentHashMap工作原理的要点分析
简介: 本文主要介绍Java8中的并发容器ConcurrentHashMap的工作原理,和其它文章不同的是,本文重点分析了不同线程的各类并发操作如get,put,remove之间是如何同步的,以及这些 ...
- Java 编程要点之并发(Concurrency)详解
计算机用户想当然地认为他们的系统在一个时间可以做多件事.他们认为,他们可以工作在一个字处理器,而其他应用程序在下载文件,管理打印队列和音频流.即使是单一的应用程序通常也是被期望在一个时间来做多件事.例 ...
- Java面试通关要点汇总集
Java面试通关要点汇总集 2018-03-09 转自:Java面试通关要点汇总集 文章目录 1. 基础篇 1.1. 基本功 1.2. 集合 1.3. 线程 1.4. 锁机制2. 核心篇 2 ...
- ConcurrentHashMap基于JDK1.8源码剖析
前言 声明,本文用的是jdk1.8 前面章节回顾: Collection总览 List集合就这么简单[源码剖析] Map集合.散列表.红黑树介绍 HashMap就是这么简单[源码剖析] LinkedH ...
- ConcurrentHashMap 源码阅读小结
前言 每一次总结都意味着重新开始,同时也是为了更好的开始.ConcurrentHashMap 一直是我心中的痛.虽然不敢说完全读懂了,但也看了几个重要的方法,有不少我觉得比较重要的知识点. 然后呢,放 ...
- 并发编程——ConcurrentHashMap#addCount() 分析
前言 ConcurrentHashMap 精华代码很多,前面分析了 helpTransfer 和 transfer 和 putVal 方法,今天来分析一下 addCount 方法,该方法会在 putV ...
随机推荐
- Qt消息机制和事件(二)
三,事件过滤器 有时候,对象需要查看.甚至要拦截发送到另外对象的事件.例如,对话框可能想要拦截按键事件,不让别的组件接收到:或者要修改回车键的默认处理. 通过前面的章节,我们已经知道,Qt 创建了QE ...
- rac 11g_第二个节点重启后无法启动实例:磁盘组dismount问题
原创作品,出自 "深蓝的blog" 博客,欢迎转载,转载时请务必注明以下出处,否则追究版权法律责任. 深蓝的blog:http://blog.csdn.net/huangyanlo ...
- kmeans算法
# coding:utf-8 import numpy as np import matplotlib.pyplot as plt def dis(x, y): #计算距离 return np.sum ...
- 你足够了解Context吗?
你足够了解Context吗? 这里有关于Context的一切-写在前面: 当我还是一个24K纯Android新手的时候(现在是也是个小Android萌新),拿着工具书对着电脑敲敲打打,那个时候我就有一 ...
- 学习tornado:安全
http://blog.csdn.net/siddontang/article/details/18053915
- C++ const使用详解
1.const常量和宏常量const int max=100;#define max 100;const常量相对宏常量有两个有点:1)有类型安全检查2)占用内存空间少 2.const变量在内存中的位置 ...
- WCF入门教程四[WCF的配置文件]
一.概述 配置也是WCF编程中的主要组成部分.在 以往的.net应用程序中,我们会把DBConn和一些动态加载类及变量写在配置文件里.但WCF有所不同.他指定向客户端公开的服务,包括服务的地址. 服务 ...
- PHP使用session_set_save_handler陷阱
陷阱如下 当脚本使用了session_set_save_handler 来重定向 session后,使用session_destroy后再使用session_start()重新开启session会报错 ...
- python数据类型之str用法
1.首字母大写 语法:S.capitalize() -> str title = "today is a good day" title_ca = title.capital ...
- centos 6.5 下载
https://wiki.centos.org/Manuals/ReleaseNotes/CentOS6.5 sha1sum i386: 67ea68068ae53d1f23431072ec0288b ...