ConcurrentHashMap、synchronized与线程安全
来源:互联网 发布:淘宝招聘在家工作 编辑:程序博客网 时间:2024/06/06 08:29
最近做的项目中遇到一个问题:明明用了ConcurrentHashMap,可是始终线程不安全
除去项目中的业务逻辑,简化后的代码如下:
测试代码跑了10次,每次都不是800。这就很让人疑惑了,难道ConcurrentHashMap的线程安全性失效了?
查了一些资料后发现,原来ConcurrentHashMap的线程安全指的是,它的每个方法单独调用(即原子操作)都是线程安全的,但是代码总体的互斥性并不受控制。以上面的代码为例,最后一行中的:
实际上并不是原子操作,它包含了三步:
- map.get
- 加1
- map.put
其中第1和第3步,单独来说都是线程安全的,由ConcurrentHashMap保证。但是由于在上面的代码中,map本身是一个共享变量。当线程A执行map.get的时候,其它线程可能正在执行map.put,这样一来当线程A执行到map.put的时候,线程A的值就已经是脏数据了,然后脏数据覆盖了真值,导致线程不安全
简单地说,ConcurrentHashMap的get方法获取到的是此时的真值,但它并不保证当你调用put方法的时候,当时获取到的值仍然是真值
为了使上面的代码变得线程安全,我引入了synchronized关键字来修饰目标方法,如下:
运行之后仍然是线程不安全的,难道synchronized也失效了?
查阅了synchronized的资料后,原来,不管synchronized是用来修饰方法,还是修饰代码块,其本质都是锁定某一个对象。修饰方法时,锁上的是调用这个方法的对象,即this;修饰代码块时,锁上的是括号里的那个对象
在上面的代码中,很明显就是锁定的MyTask对象本身。但是由于在每一个线程中,MyTask对象都是独立的,这就导致实际上每个线程都对自己的MyTask进行锁定,而并不会干涉其它线程的MyTask对象。换言之,上锁压根没有意义
理解到这点之后,对上面的代码又做了一次修改:
此时在调用addup时直接锁定map,由于map是被所有线程共享的,因而达到了让所有线程互斥的目的,线程安全达成。
注意:
synchronized {普通方法}依靠对象锁工作,多线程访问synchronized方法,一旦某个进程抢得锁之后,其他的进程只有排队对待。synchronized void method{}功能上,等效于
void method{
synchronized(this) {
...
}
}
2.synchronized {static方法}此代码块等效于
void method{
synchronized(Obl.class)
}
}
使用该类的类对象的锁定去做线程的共享互斥.
在spring源码中的使用:DefaultListableBeanFactory.java registerBeanDefinition
- /** Map of bean definition objects, keyed by bean name */
- private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(64);
- //---------------------------------------------------------------------
- // Implementation of BeanDefinitionRegistry interface
- //---------------------------------------------------------------------
- public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
- throws BeanDefinitionStoreException {
- Assert.hasText(beanName, "Bean name must not be empty");
- Assert.notNull(beanDefinition, "BeanDefinition must not be null");
- if (beanDefinition instanceof AbstractBeanDefinition) {
- try {
- ((AbstractBeanDefinition) beanDefinition).validate();
- }
- catch (BeanDefinitionValidationException ex) {
- throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
- "Validation of bean definition failed", ex);
- }
- }
- BeanDefinition oldBeanDefinition;
- synchronized (this.beanDefinitionMap) {
- oldBeanDefinition = this.beanDefinitionMap.get(beanName);
- if (oldBeanDefinition != null) {
- if (!this.allowBeanDefinitionOverriding) {
- throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(),beanName,
- "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
- "': There is already [" + oldBeanDefinition + "] bound.");
- }
- else {
- if (this.logger.isInfoEnabled()) {
- this.logger.info("Overriding bean definition for bean '" + beanName +
- "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
- }
- }
- }
- else {
- this.beanDefinitionNames.add(beanName);
- this.frozenBeanDefinitionNames = null;
- }
- this.beanDefinitionMap.put(beanName, beanDefinition);
- }
- if (oldBeanDefinition != null || containsSingleton(beanName)) {
- resetBeanDefinition(beanName);
- }
- }
- ConcurrentHashMap、synchronized与线程安全
- ConcurrentHashMap、synchronized与线程安全
- ConcurrentHashMap、synchronized与线程安全
- ConcurrentHashMap、synchronized与线程安全
- ConcurrentHashMap、synchronized与线程安全
- ConcurrentHashMap、synchronized与线程安全
- ConcurrentHashMap、synchronized与线程安全
- 并发容器ConcurrentHashMap与synchronized联合使用达到线程安全
- 线程安全之ConcurrentHashMap
- ConcurrentHashMap线程安全
- java synchronized详解 线程安全与线程非安全
- 【Java多线程】synchronized与线程安全
- 【多线程】实例变量(synchronized)与线程安全
- synchronized ReentrantLock 线程安全
- synchronized 线程同步安全
- 【Java】 线程安全 synchronized
- Synchronized和线程安全
- ConcurrentHashMap 线程安全的 HashMap
- 二叉树的镜像
- CMS垃圾收集器执行过程
- Jetson TX1 安装Caffe教程
- UIEdgeInsetsMake使用详解
- poj3258 二分
- ConcurrentHashMap、synchronized与线程安全
- 2017.11.17-22:41
- 实用工具合集
- JAVA反射(三)之动态代理
- HTML/CSS面试题(收集)
- 使用Django从数据库中随机取N条记录的不同方法及其性能实测
- Find Hao 的奇技淫巧 之 快速下载
- window.open()打开窗口的几种方式
- Web单词整理