`

Map浅析

 
阅读更多

java.Util.Map接口是jdk的常用接口,Map是一种数据字典,以key,value形式出现,key、value作为数据域出现在内部接口Entry<K,V>中。提供根据key查value,以及keys和values集合并遍历的方法。没什么特殊的地方,只是对于几种Map,如果能知道其数据结构和相对优劣,对于编写性能较好的程序是需要掌握这些的。

 

1.Hashtable

jdk的遗留类。提供了线程安全的添加、删除等接口,通过内部互斥锁Synchronized实现。

 

public synchronized V put(K key, V value)
public synchronized V get(Object key)

 

 

2.HashMap

数据结构是数组,数组元素是单向链表。数据结构如下图:


 

常用方法:

put(key,value)

1)如果key为null

如果key==null,则执行putForNullKey()。HashMap只允许存在一个key为null的元素,value后值覆盖前值。

 

2)计算key的hash值

根据jdk的hash算法,计算key的hash值。

 

3)定位元素在数组中的位置

执行indexFor()方法,得到元素在数组中的index。

 

4)数组中已存在相同的key

遍历数组,判断数组中是否已经有相同的key,已经存在,则value后值覆盖前值,返回oldValue。

判断条件是两个key的hash值相同,并且两者的”==”或者“equals”比较返回true。如果key是String对象,则内容相同或者是同一个对象都判定为key相同;如果是自定义对象,则需要重写equals方法来规定判断标准。如果以自定义的对象作为key,则需要重写equals()和hashcode()。

 

5)数组中不存在该key

将元素包装为Entry类型,添加元素到数组,并将新Entry对象添加到链表头。

 

 特点:

1)可以存储null键和null值,Hashtable不允许;

两个关键参数:initial capacity和load factor。Load factor默认是0.75,是offers a good tradeoff between time and space costs。当map元素数量大于集合容量乘以加载因子时,集合容量扩大到当前容量的两倍,并且对元素进行rehash。尽量避免rehash,如果初始容量大于最大元素数除以加载因子时,则不会发生rehash。

 

2)非线程安全。

典型的问题是多线程并发访问、rehash时,会产生死循环问题。可使用Collections.synchronizedMap 方法来“包装”该映射,实现并发的安全处理。如果Collections.synchronizedMap不能满足性能要求,可试试选择ConcurrentHashMap。

 

3)迭代的快速失败。

集合的迭代器创建之后,如果集合结构有修改,而且非调用Iterator.remove(),迭代器会抛出 ConcurrentModificationException,但是该fail-fast得不到保证的。参考iterator方法,可知在遍历Iterator期间,元素个数有变化,则出现并发问题,抛出异常。

 

Step1
private final class KeySet extends AbstractSet<K> {
  public Iterator<K>iterator() {
    return new KeyIterator();
  }
  publicint size() {
    returnsize;
  }
  public boolean contains(Object o) {
    return containsKey(o);
  }
  public boolean remove(Object o) {
    return HashMap.this.removeEntryForKey(o) != null;
  }
  public void clear() {
    HashMap.this.clear();
  }
}
Step2
Iterator<K> newKeyIterator()   {
  retur nnew KeyIterator();
}
Step3
private final class KeyIterator extends HashIterator<K> {
  public K next() {
    return nextEntry().getKey();
  }
}
Step4
final Entry<K,V> nextEntry() {
  if (modCount != expectedModCount)
    throw new ConcurrentModificationException();

  Entry<K,V> e = next;
  if (e == null)
    throw new NoSuchElementException();

  if ((next = e.next) == null) {
      Entry[] t = table;
      while (index< t.length&& (next = t[index++]) == null)
        ;
  }
current = e;
return e;
}

 

4)线程安全

HashMap为什么是非线程安全的?ConcurrentHashMap为什么是线程安全的?

HashMap数据结构是Entry数组,并发操作时,数组是被竞争的共享资源,如果读时有写操作,就会出现并发问题。

 

HashMap提供了fast-fail机制,使用Iterator遍历时,会比较元素更新数,如果元素数有变化,则抛出ConcurrentModificationException。

 

ConcurrentHashMap数据结构是Segment数组,每个数组上通过加显示锁保证了线程安全。同时,由于元素分成了多个segment,提高了并发性能。实现参考ConcurrentHashMap部分。

 

3.LinkedHashMap

1)数据结构

数据保存在一个数组,数组元素是双向链表。

private transient Entry<K,V>header;//数组
 
private static class Entry<K,V> extends HashMap.Entry<K,V>{
Entry<K,V> before, after;//双向指针
…
}

  

2)特点

LinkedHashMap保存了数据的插入顺序。在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的;HashMap返回key-value的顺序只与Key的hashCode有关。

 

LinkedHashMap也可以在构造时用带参数,按照应用次数排序。在遍历的时候会比HashMap慢,不过有种情况例外,当HashMap容量很大,实际数据较少时,遍历起来可能会比LinkedHashMap慢,因为LinkedHashMap的遍历速度只和容量有关,而HashMap的遍历速度和他的碰撞情况相关。

 

5.ConcurrentHashMap

1)数据结构



 

 

2)特点

a)并发安全

通过对segment对象加锁,实现了该segment内读写操作的互斥,保证了并发安全性。 

 

b)并发性能好

ConcurrentHashMap数据保存在名为segments的数组中,锁是分别加在每个segement上的,与Hashtable、Collections.synchronizedMap相比,多个segment之间可以安全的并发操作,提高了并发性能。

 

代码实现

参考获取操作的实现代码。

Step1
public V get(Object key) {
  int hash = hash(key.hashCode());
  return segmentFor(hash).get(key, hash);
}

Step2
V get(Object key, int hash) {
  if (count != 0) { // read-volatile
    HashEntry<K,V> e = getFirst(hash);

  while (e != null) {
    if (e.hash == hash && key.equals(e.key)) {
      V v = e.value;
      if (v != null)
        return v;
      return readValueUnderLock(e); // recheck
    }
    e = e.next;
  }
 }
 return null;
}

Step3
V readValueUnderLock(HashEntry<K,V> e) {
  lock();
  try {
    return e.value;
  } finally {
    unlock();
  }
}

 

6.TreeMap

TreeMap数据结构是红黑树。实现了SortMap接口,能够把它保存的记录根据键排序,默认是按键值升序排序,也可以指定排序的比较器。(数据结构及分析待补充)

 

  • 大小: 13.5 KB
  • 大小: 36.7 KB
0
1
分享到:
评论

相关推荐

    MAP文件浅析(正点原子)-V1.0

    MAP文件浅析(正点原子)-V1.0 MAP文件浅析是MDK编译生成文件之一,顾名思义,它是一种映射文件,记录了编译过程中的各个阶段信息,包括生成的目标文件、符号表、程序段交叉引用关系、映像内存分布图等重要信息。...

    lidaohang#ceph_study#Ceph OSDMap 机制浅析1

    在 OSDMap 数据中 Pool 集合,副本数,PG 数量,OSD 集合这 4 项由运维人员来指定,虽然 OSD 的状态也可以由运维人员进行更改,但是实际运行

    基于MAPSOURCE交换格式实现GPS航点批量输入浅析.pdf

    《基于MAPSOURCE交换格式实现GPS航点批量输入浅析》 本文主要探讨如何利用MAPSOURCE交换格式实现GPS航点的批量输入,以提高地质工作的效率。Mapsource是一款常见的GPS数据处理软件,它允许用户在GPS设备和计算机...

    浅析go中的map数据结构字典

    Go语言中的map是一种内置的数据结构,它实现为哈希表,提供键(Key)到值(Value)的存储能力。使用map可以实现快速的键值查找,其核心特点包括: 1. 键必须是可比较的类型,即支持使用"=="操作符进行比较。例如,...

    浅析Java8 中 Map 接口的新方法

    浅析Java8 中 Map 接口的新方法 Java8 中 Map 接口的新方法是指 Java8 中引入的一些新的方法,用于提高 Map 接口的使用效率和便捷性。在本文中,我们将详细介绍 Java8 中 Map 接口的新方法,并通过代码实例来演示其...

    浅析scala中map与flatMap的区别

    Scala 中 map 与 flatMap 的区别 在 Scala 中,map 和 flatMap 是两个非常重要的函数,它们都是函数式编程中的核心概念。虽然它们都可以将一个函数应用于集合中的每个元素,但是它们之间存在着很大的区别。 首先,...

    浅析JS中的 map, filter, some, every, forEach, for in, for of 用法总结

    1.map 有返回值,返回一个新的数组,每个元素为调用func的结果。 let list = [1, 2, 3, 4, 5]; let other = list.map((d, i) =&gt; { return d * 2; }); console.log(other); // print: [2, 4, 6, 8, 10] 2.filter 有...

    WordCount 源码浅析(1)

    《WordCount 源码浅析(1)》 在大数据处理领域,Hadoop 是一个不可或缺的名字,而 WordCount 是 Hadoop 的经典示例程序,它用于统计文本中单词出现的频率。这篇博客将对 WordCount 的源码进行初步解析,帮助初学者...

    浅析java中遍历map的两种方式

    在Java编程中,Map接口是一个非常重要的数据结构,它存储键值对,其中每个键都是唯一的。遍历Map是开发过程中常见的操作,通常有两种主要的方法:通过Entry Set和通过Key Set。下面将详细介绍这两种遍历方式。 1. ...

    浅析stl序列容器(map和set)的仿函数排序

    在本文中,我们将深入探讨如何使用仿函数对STL序列容器`map`和`set`进行自定义排序。 `set`和`map`都是STL中有序的容器。`set`是一个无重复元素的集合,而`map`则是一组键值对,其中键是唯一的。它们都使用红黑树...

    浅析php中array_map和array_walk的使用对比

    - **map vs walk**:`array_map()` 是为了获取处理后的新数组,关注结果;而 `array_walk()` 更注重过程,可以用于执行不返回值的操作,如调试、打印或直接修改数组。 - **参数传递**:`array_walk()` 可以通过 `$...

    浅析Java中Map与HashMap,Hashtable,HashSet的区别

    在Java编程语言中,`Map`接口是用于存储键值对的数据结构,它不保证元素的顺序,允许null键和null值。`HashMap`、`Hashtable`和`HashSet`都是基于`Map`或`Set`接口实现的不同数据结构,它们在功能、线程安全性和性能...

    Hadoop应用系列2--MapReduce原理浅析(上)

    《Hadoop应用系列2--MapReduce原理浅析(上)》 MapReduce是Apache Hadoop框架的核心组件之一,主要用于处理和生成大规模数据集。本文将深入浅出地探讨MapReduce的工作原理,帮助读者理解其核心概念和流程。 一、...

    Python中的map、reduce和filter浅析

    1、先看看什么是 iterable 对象 以内置的max函数为例子,查看其doc:复制代码 代码如下:&gt;&gt;&gt; print max.__doc__max(iterable[, key=func]) -&gt; valuemax(a, b, c, …[, key=func]) -&gt; value With a single iterable ...

    浅析MFC程序基本运行机制

    ### 浅析MFC程序基本运行机制 #### 一、MFC简介与特点 MFC(Microsoft Foundation Classes)是微软为简化Windows编程而提供的一套类库,它基于C++语言,封装了大量的Windows API,使得开发者能够更高效、更简单地...

    Hadoop+HDFS和MapReduce架构浅析

    ### Hadoop+HDFS和MapReduce架构浅析 #### 摘要 本文旨在深入剖析Hadoop中的两大核心组件——HDFS(Hadoop Distributed File System)和MapReduce的工作原理及其实现机制。首先,我们将介绍Hadoop NameNode与...

    Java 集合浅析.txt

    ### Java集合浅析 #### 一、概述 Java集合框架是Java编程语言中处理数据结构的一个强大工具包,它提供了一系列灵活高效的接口和实现来帮助开发者管理数据。本篇文章将重点介绍Java中常用的集合类——`Collection`...

    HDFS性能压测工具浅析

    SliveTest是另一种专门用于测试Namenode性能的工具,它通过大量map任务模拟各种RPC操作,如ls(列出文件和目录)、append(追加写文件)、create(创建文件)、delete(删除文件)、mkdir(创建目录)、rename(重命名文件)和...

Global site tag (gtag.js) - Google Analytics