Java多线程工具包java.util.concurrent---ConcurrentHashMap
Posted yvan1115
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java多线程工具包java.util.concurrent---ConcurrentHashMap相关的知识,希望对你有一定的参考价值。
参考以下博客
http://blog.csdn.net/xiaohui127/article/details/11928865
http://blog.csdn.net/xuefeng0707/article/details/40797085
http://www.importnew.com/21388.html
本文没有具体探讨ConcurrentHashMap、HashMap、HashTable的实现,只是对其做了比较和总结,在工作中该如何使用,避免不必要的错误
什么是ConcurrentHashMap
ConcurrentHashMap 和 java.util.HashTable 类很相似,但 ConcurrentHashMap 能够提供比 HashTable 更好的并发性能。在你从中读取对象的时候 ConcurrentHashMap 并不会把整个 Map 锁住。此外,在你向其中写入对象的时候,ConcurrentHashMap 也不会锁住整个 Map。它的内部只是把 Map 中正在被写入的部分进行锁定。
另外一个不同点是,在被遍历的时候,即使是 ConcurrentHashMap 被改动,它也不会抛 ConcurrentModificationException。
有什么特点
1、允许并发的读和线程安全的更新操作
2、在执行写操作时,只锁住部分的Map
- 这里说明以下同为线程安全的HashTable,主要区别在于
ConcurrentHashMap是分段锁(Segmentation),而HashTable是锁住整个map,在并发性能上ConcurrentHashMap优于HashTable
3、并发的更新是通过内部根据并发级别将Map分割成小部分实现的
4、高的并发级别会造成时间和空间的浪费,低的并发级别在写线程多时会引起线程间的竞争
5、所有操作都是线程安全
6、返回的迭代器是弱一致性,fail-safe并且不会抛出ConcurrentModificationException异常
7、不允许null的键值
- key和value都不允许为null
8、可以使用ConcurrentHashMap代替HashTable,但要记住ConcurrentHashMap不会锁住整个Map
HashMap造成cpu100%的问题
Java HashMap的死循环
这篇文章详细介绍了多线程下HashMap在rehash过程中造成死循环,引起cpu100%的过程和原因。
简单来说:由于rehash的机制,多线程下使hashmap内部形成了环形链表.
示例
这里简单写一个利用线程安全的特点ConcurrentHashMap作为数据缓存。
ConcurrentHashMap比较适合多读少写的场景
class AddressData
private static ConcurrentMap<String, Object> map = new ConcurrentHashMap<>();
public static Object getData(String param)
Object result = null;
try
result = map.get(param);
if (result == null)
HttpHelper helper = new HttpHelper();
// 如果key已经存在,那么返回的值就是key对应的value
// 如果key不存在,那么返回的值为null
map.putIfAbsent(param, helper.getProviceCityArea());
result = map.get(param);
catch (Exception e)
// TODO 异常管理
return result;
class HttpHelper
public Address getProviceCityArea()
Address address = new Address();
address.setProviceCode("1");
address.setProviceCode("四川省");
List<City> cites = new ArrayList<>();
City city = new City();
city.setCityCode("10");
city.setCityName("成都市");
List<Area> areas = new ArrayList<>();
Area area = new Area();
area.setAreaCode("101");
area.setAreaName("锦江区");
areas.add(area);
city.setAreas(areas);
cites.add(city);
address.setCites(cites);
return address;
class Address
private String proviceCode;
private String proviceName;
private List<City> cites;
public String getProviceCode()
return proviceCode;
public void setProviceCode(String proviceCode)
this.proviceCode = proviceCode;
public String getProviceName()
return proviceName;
public void setProviceName(String proviceName)
this.proviceName = proviceName;
public List<City> getCites()
return cites;
public void setCites(List<City> cites)
this.cites = cites;
@Override
public String toString()
return "Address [proviceCode=" + proviceCode + ", proviceName=" + proviceName + ", cites=" + cites.toString()
+ "]";
class City
private String cityCode;
private String cityName;
private List<Area> areas;
public String getCityCode()
return cityCode;
public void setCityCode(String cityCode)
this.cityCode = cityCode;
public String getCityName()
return cityName;
public void setCityName(String cityName)
this.cityName = cityName;
public List<Area> getAreas()
return areas;
public void setAreas(List<Area> areas)
this.areas = areas;
@Override
public String toString()
return "City [cityCode=" + cityCode + ", cityName=" + cityName + ", areas=" + areas.toString() + "]";
class Area
private String areaCode;
private String areaName;
public String getAreaCode()
return areaCode;
public void setAreaCode(String areaCode)
this.areaCode = areaCode;
public String getAreaName()
return areaName;
public void setAreaName(String areaName)
this.areaName = areaName;
@Override
public String toString()
return "Area [areaCode=" + areaCode + ", areaName=" + areaName + "]";
探讨示例
前面提到的concurrentHashMap线程安全,主要是利用了分段锁来实现,保证在每次访问只允许一个线程修改哈希表的映射关系
但是是否具有原子性?
ConcurrentMap能够保证每一次调用(例如一次putIfAbsent)都是原子操作,不受多线程影响,但并不保证多次调用之间也是原子操作
package com.yvan.concurrentMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
/**
*
* @author yvan
*
*/
public class AppMain
private static ConcurrentHashMap<Integer, Integer> map = new ConcurrentHashMap<Integer, Integer>();
public static void main(String[] args) throws InterruptedException
CountDownLatch countDownLatch = new CountDownLatch(3);
map.put(3, 1);
new Thread("Thread1")
@Override
public void run()
System.out.println(Thread.currentThread().getName()+"s=="+map.get(3));
int temp = map.get(3)+1;
map.put(3, temp);
System.out.println(Thread.currentThread().getName()+"e=="+map.get(3));
countDownLatch.countDown();
.start();
new Thread("Thread2")
@Override
public void run()
System.out.println(Thread.currentThread().getName()+"s=="+map.get(3));
int temp = map.get(3)+1;
map.put(3, temp);
System.out.println(Thread.currentThread().getName()+"e=="+map.get(3));
countDownLatch.countDown();
.start();
new Thread("Thread3")
@Override
public void run()
System.out.println(Thread.currentThread().getName()+"s=="+map.get(3));
int temp = map.get(3)+1;
map.put(3, temp);
System.out.println(Thread.currentThread().getName()+"e=="+map.get(3));
countDownLatch.countDown();
.start();
countDownLatch.await();
System.out.println(map.get(3));
结果
Thread1s==1
Thread1e==2
Thread2s==1
Thread2e==3
Thread3s==3
Thread3e==4
4
以上是关于Java多线程工具包java.util.concurrent---ConcurrentHashMap的主要内容,如果未能解决你的问题,请参考以下文章
Java多线程工具包java.util.concurrent---CyclicBarrier
Java多线程工具包java.util.concurrent---ExecutorService
Java多线程工具包java.util.concurrent---ReadWriteLock