【源码解读】JDK1.8 中 ConcurrentHashMap 不支持空键值对源码剖析

>>号外:关注“Java精选”公众号,回复“2021面试题”,领取免费资料!“Java精选面试题”小程序,3000+ 道面试题在线刷,最新、最全 Java 面试题!

首先明确一点HashMap是支持空键值对的,也就是null键和null值,而ConcurrentHashMap是不支持空键值对的。

查看一下JDK1.8源码,HashMap类部分源码,代码如下:

public V get(Object key) {
        Node<K,V> e;
        return (e = getNode(hash(key), key)) == null ? null : e.value;
}
static final int hash(Object key) {
	int h;
	return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

HashMap在调用put()方法存储数据时会调用hash()方法来计算key的hashcode值,可以从hash()方法上得出当key==null时返回值是0,这意思就是key值是null时,hash()方法返回值是0,不会再调用key.hashcode()方法。

ConcurrentHashMap类部分源码,代码如下:

public V put(K key, V value) {
	return putVal(key, value, false);
}
/** Implementation for put and putIfAbsent */
final V putVal(K key, V value, boolean onlyIfAbsent) {
	if (key == null || value == null) throw new NullPointerException();
	int hash = spread(key.hashCode());
	int binCount = 0;
	for (Node<K,V>[] tab = table;;) {
		Node<K,V> f; int n, i, fh;
		if (tab == null || (n = tab.length) == 0)
			tab = initTable();
		else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
			if (casTabAt(tab, i, null,
						 new Node<K,V>(hash, key, value, null)))
				break;                   // no lock when adding to empty bin
		}
		else if ((fh = f.hash) == MOVED)
			tab = helpTransfer(tab, f);
		else {
			V oldVal = null;
			synchronized (f) {
				if (tabAt(tab, i) == f) {
					if (fh >= 0) {
						binCount = 1;
						for (Node<K,V> e = f;; ++binCount) {
							K ek;
							if (e.hash == hash &&
								((ek = e.key) == key ||
								 (ek != null && key.equals(ek)))) {
								oldVal = e.val;
								if (!onlyIfAbsent)
									e.val = value;
								break;
							}
							Node<K,V> pred = e;
							if ((e = e.next) == null) {
								pred.next = new Node<K,V>(hash, key,
														  value, null);
								break;
							}
						}
					}
					else if (f instanceof TreeBin) {
						Node<K,V> p;
						binCount = 2;
						if ((p = ((TreeBin<K,V>)f).putTreeVal(hash, key,
													   value)) != null) {
							oldVal = p.val;
							if (!onlyIfAbsent)
								p.val = value;
						}
					}
				}
			}
			if (binCount != 0) {
				if (binCount >= TREEIFY_THRESHOLD)
					treeifyBin(tab, i);
				if (oldVal != null)
					return oldVal;
				break;
			}
		}
	}
	addCount(1L, binCount);
	return null;
}

ConcurrentHashmap在调用put()方法时调用了putVal()方法,而在该方法中判断key为null或value为null时抛出空指针异常NullPointerException。

ConcurrentHashmap是支持并发的,当通过get()方法获取对应的value值时,如果指定的键为null,则为NullPointerException,这主要是因为获取到的是null值,无法分辨是key没找到null还是有key值为null。

往期精选  点击标题可跳转

面试官问:为什么 Java 线程没有 Running 状态?一下被问懵!

SpringBoot + Mybatis + Druid + PageHelper 实现多数据源并分页(附源码)

Intellij IDEA 中的各种调试代码技巧,轻松定位 Bug 问题(涵盖超全面)

MyBatis 真坑!Integer 类型赋值 0 ,当 != '' 时无法通过判断执行 SQL 语句

面试官问:Spring Boot 中实现通用 Auth 认证,有哪几种方式?

Spring 中 IService 有多个实现类,它是如何知道该注入哪个 ServiceImpl 类?

突然慌了!面试官问:线程池中多余的线程是如何回收的?

MySQL 数据库中百万级数据量,大神是如何分页查询?

数据库中 SQL 语句使用索引,还是很慢?可能是这几点原因

Spring Boot 框架中实现跨域访问的五种解决方案,你懂了吗?

面试官问:导致 Spring 事务失效的场景有哪些,如何解决失效问题?

点个赞,就知道你“在看”!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值