Java基础-Map容器的并发访问控制
2016-02-15 23:00
357 查看
在并发环境中,多线程之间共享数据时,需要对数据访问进行并发控制。例如,经典的生产者-消费者的实例中,生产线程和消费线程共享同一个容器对象,那么必须使用线程安全的容器对象。
简单的使用HashMap,存储信息后,统计某些key的出现次数,正确的并发控制代码如下:
import java.util.HashMap;
public class SharedMap {
private HashMap<String,Integer> map = new HashMap<>();
public synchronized void add(String key){
Integer value = map.get(key);
if(value==null){
map.put(key, 1);
}else{
map.put(key, value+1);
}
}
}
由于并发环境下,对map对象的访问操作中,get和put是一起的原子操作,所以最简单的就是使用内置锁进行同步控制。java并发包中还有一个适用于并发环境下的高效的容器类ConcurrentHashMap,这个类中没有对整个Map加锁独占访问的支持,它使用了一种更细粒度的加锁机制即分段锁。由于每个bucket桶元素都对应一个段锁,所以大并发环境下能允许一定数量的线程并发第put数据(因为不同的key来说,put操作使用的都是对应的段锁,它们的段锁匙不同的,所以不容易造成阻塞等待)。所以,在并发环境下,这个类更容易实现高效的吞吐量。
那么上述代码如果使用ConcurrentHashMap的话,该如何修改呢?如果直接去掉synchronized的话,这段并发控制的代码存在什么问题呢?因为ConcurrentHashMap类并不能保证原子性,而上述代码的方法体所有语句都应该是一个子则操作,所以即使是换成这个类型,也还是需要加锁的。
简单的使用HashMap,存储信息后,统计某些key的出现次数,正确的并发控制代码如下:
import java.util.HashMap;
public class SharedMap {
private HashMap<String,Integer> map = new HashMap<>();
public synchronized void add(String key){
Integer value = map.get(key);
if(value==null){
map.put(key, 1);
}else{
map.put(key, value+1);
}
}
}
由于并发环境下,对map对象的访问操作中,get和put是一起的原子操作,所以最简单的就是使用内置锁进行同步控制。java并发包中还有一个适用于并发环境下的高效的容器类ConcurrentHashMap,这个类中没有对整个Map加锁独占访问的支持,它使用了一种更细粒度的加锁机制即分段锁。由于每个bucket桶元素都对应一个段锁,所以大并发环境下能允许一定数量的线程并发第put数据(因为不同的key来说,put操作使用的都是对应的段锁,它们的段锁匙不同的,所以不容易造成阻塞等待)。所以,在并发环境下,这个类更容易实现高效的吞吐量。
那么上述代码如果使用ConcurrentHashMap的话,该如何修改呢?如果直接去掉synchronized的话,这段并发控制的代码存在什么问题呢?因为ConcurrentHashMap类并不能保证原子性,而上述代码的方法体所有语句都应该是一个子则操作,所以即使是换成这个类型,也还是需要加锁的。
相关文章推荐
- 【JAVA】11、选择结构
- 研究一下 项目 webservice xml和java对象的相互自动转换,json和java对象的相互自动转换
- Windows 7/10 myeclipse hadoop2.7.1 连接和操作
- ***使用spring webflow遇到的问题-2***
- 【JAVA】10、程序的3种结构
- OData的Java实现(一)
- java的struts2整理
- Java设计模式之二:抽象工厂AbstractFactory
- Java虚拟机(JVM)
- java Map及Map.Entry详解
- 原生态JAVAEE酒店管理系统系列二
- struts2学习笔记--上传单个和批量文件示例
- 从头认识Spring-2.4 基于java的标准注解装配-@Inject(3)-通过构造器方法注入
- 原生态JAVAEE酒店管理系统系列一 之编码之前的环境准备
- 六种常用的设计模式java实现(一)工厂模式
- 从头认识Spring-2.4 基于java的标准注解装配-@Inject(2)-通过set方法或者其他方法注入
- spring简单概念
- MyEclipse 启动不了
- 从头认识Spring-2.4 基于java的标准注解装配-@Inject(1)-通过属性域注入
- Quartz与Spring的整合使用