真正学会Java之Map

我通过脑图总结了map的知识点,上图!

JavaMap水印.png

一、计算Hash的方法有哪些?

  • time 33
  • MurmurHash

像redis 就用到了上面两种hash算法,hadoop、nginx 都用到了MurmurHash。

time33算法:简单高效,就是不断的乘33,和Java String的hashCode()方法很像:

  //hash << 5 相当于 hash * 33
(hash = ((hash << 5) + hash) + (*str);)

MurmurHash算法:高运算性能,低碰撞率。而且google开源的guava给出了实现,我在工作中,曾用该方法对移动设备的DeviceId进行hash计算取模,非常的均匀:

Hashing.murmur3_128().hashString("test", Charset.forName("UTF-8")).asLong();

二、Java中的Object.hashCode方法与内存地址有关系吗?

Java中Java中的Object.hashCode方法是一个native方法,通过查一些资料得知,至少在OpenJDK中,默认hashCode()实现,与对象的内存地址无关。在版本6和7中,它是一个随机生成的数字。在8中,它是基于线程状态的数字。调用一次hashCode之后,其hashCode缓存在其对象头字段里,以便之后使用。

三、redis 中百万数据如何扩容知多少?和hashMap有何不同?

redis 中的数据结构也是 数组 + 链表实现。当redis中的数据越来越大,它是如何扩容呢?怎么做才不影响数据的访问和保存呢?
redis中有2个hash表,ht[0]和ht[1],开始只使用ht[0],如果需要扩容时,把rehashidx标识字段从-1改为0,标识需要扩容,给Hash表ht[1]申请当前容量2倍空间,新添加的键值往ht[1]存储,修改、删除、查找,需要在ht[0]和ht[1]都检索,两个hash表同时可用。执行插入、删除、查找、修改等操作前,都先判断当前字典rehash操作是否在进行中,是的话调用方法执行一个节点迁移,并且空闲时迁移,每次对100个节点迁移,直到rehash结束后,其中一个清空,并设置rehashidx标识字段为-1,完成扩容操作,耗时忽略不计。大神就是大神啊,如此之巧妙。

四、kafka中的读写分离Map之CopyOnWriteMap

kafka 的KafkaProducer在发送消息的时候,不是直接发送,而是放到一个CopyOnWriteMap结构的缓存池中,当缓存已满时,才唤醒发送线程,发送消息。提高吞吐量。CopyOnWriteMap 跟CopyOnWriteArrayList原理一样,volatile修饰map,添加时加锁,copy一份修改完之后替换变量,避免写对读的影响。

五、日常工作中的一些使用和技巧

  • apache.commons.collections包下多key Map的使用
MultiKeyMap multiKeyMap = new MultiKeyMap<>();
multiKeyMap.put("a","b","b","d");
multiKeyMap.put("c","d","b","d");
System.out.println(multiKeyMap.get("a","b","b"));
  • apache.commons.collections包下一个key多个value的Map的使用
MultiValueMap multiValueMap = new MultiValueMap();
multiValueMap.put("a", "a");
multiValueMap.put("a", "b");
multiValueMap.put("a", "c");
List valueList = Lists.newArrayList(multiValueMap.getCollection("a"));
  • 遍历
//第一种,通过guava工厂创建map,最好指定大小。
Map map = Maps.newHashMapWithExpectedSize(16);
map.forEach((k, v) -> {

});

//第二种
for (Map.Entry entry : map.entrySet()) {

}
  • lambda表达式对Map强大的支持,靠万能的百度。

五、一致性Hash算法,待续。

你可能感兴趣的:(真正学会Java之Map)