不是
其实不是这样的,ConcurrentHashMap 的线程安全指的是 ConcurrentHashMap中的 put,get方法是线程安全的,也就是说在使用这两个方法时不需要额外加锁。但是这并不意味着其他使用到ConcurrentHashMap 的地方都不需要加锁。
例如下面的代码:jobMap是全局成员变量,虽然是一个ConcurrentHashMap,但是test方法依然是存在并发问题的,因为 containsKey 判断和 put 赋值非原子操作,因此在多线程场景下这个方法是需要加锁的,否则就会有线程安全问题。
class JobTest {
private Map<String, Job> jobMap = new ConcurrentHashMap();
boolean test(Job job) {
if(jobMap.containsKey(job.getId, job){
jobMap.put(job.getId,job);
return true;
}else{
log.info("任务已存在");
return false;
}
}
}
当然,其实上面的代码可以使用 ConcurrentHashMap 的 putIfAbsent 方法进行优化。
class JobTest {
private Map<String, Job> jobMap = new ConcurrentHashMap();
boolean test(Job job) {
Job job = jobMap.putIfAbsent(job.getId, job);
if(job==null){
return true;
}else{
log.info("任务已存在");
return false;
}
}
}
使用ConcurrentHashMap的putIfAbsent方法进行put操作,这个方法结果值有两种.当key存在时,不存储新value直接返回已经存在的 ke y的value;当key不存在时,存储新的value,返回NULL。由于ConcurrentHashMap的 putIfAbsent 方法内部使用了同步锁实现了原子操作,所以不需要自己额外再加锁就解决了并发问题。