不是

其实不是这样的,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 方法内部使用了同步锁实现了原子操作,所以不需要自己额外再加锁就解决了并发问题。