zoukankan      html  css  js  c++  java
  • 什么是Hash?什么是Hash算法或哈希函数?什么是map?什么是HashMap?HashMap的实现原理或者工作原理?HashMap是线程安全的吗?为什么?如何解决?

    1、什么是Hash

    Hash也称散列、哈希,对应的英文都是Hash。基本原理就是把任意长度的输入,通过Hash算法变成固定长度的输出。这个映射的规则就是对应的Hash算法,而原始数据映射后的二进制串就是哈希值。

     

    2.什么是Hash算法或哈希函数?

    (1)Hash函数(Hash算法):

    在一般的线性表、树结构中,数据的存储位置是随机的,不像数组可以通过索引能一步查找到目标元素。为了能快速地在没有索引之类的结构中找到目标元素,需要为存储地址和值之间做一种映射关系h(key),这个h就是哈希函数,

    用公式表示:

    h(key)=Addr

    h:哈希函数

    key:关键字,用来唯一区分对象的

          把线性表中每个对象的关键字通过哈希函数h(key)映射到内存单元地址,并把对象存储到该内存单元,这样的线性表存储结构称为哈希表或散列表。

    (2)在设置哈希函数时,通常要考虑以下因素:

      ○ 计算函希函数所需的时间

      ○ 关键字的长度

      ○ 哈希表的长度

      ○ 关键字的分布情况

      ○ 记录的查找频率

    (3)Hash碰撞的解决方案

    链地址法

    链表地址法是使用一个链表数组,来存储相应数据,当hash遇到冲突的时候依次添加到链表的后面进行处理。

     

    链地址在处理的流程如下:
    添加一个元素的时候,首先计算元素key的hash值,确定插入数组中的位置。如果当前位置下没有重复数据,则直接添加到当前位置。当遇到冲突的时候,添加到同一个hash值的元素后面,行成一个链表。这个链表的特点是同一个链表上的Hash值相同。java的数据结构HashMap使用的就是这种方法来处理冲突,JDK1.8中,针对链表上的数据超过8条的时候,使用了红黑树进行优化。

    开放地址法

    开放地址法是指大小为 M 的数组保存 N 个键值对,其中 M > N。我们需要依靠数组中的空位解决碰撞冲突。基于这种策略的所有方法被统称为“开放地址”哈希表。线性探测法,就是比较常用的一种“开放地址”哈希表的一种实现方式。线性探测法的核心思想是当冲突发生时,顺序查看表中下一单元,直到找出一个空单元或查遍全表。简单来说就是:一旦发生冲突,就去寻找下 一个空的散列表地址,只要散列表足够大,空的散列地址总能找到。

    线性探测法的数学描述是:h(k, i) = (h(k, 0) + i) mod m,i表示当前进行的是第几轮探查。i=1时,即是探查h(k, 0)的下一个;i=2,即是再下一个。这个方法是简单地向下探查。mod m表示:到达了表的底下之后,回到顶端从头开始。

    对于开放寻址冲突解决方法,除了线性探测方法之外,还有另外两种比较经典的探测方法,二次探测(Quadratic probing)和双重散列(Double hashing)。但是不管采用哪种探测方法,当散列表中空闲位置不多的时候,散列冲突的概率就会大大提高。为了尽可能保证散列表的操作效率,一般情况下,我们会尽可能保证散列表中有一定比例的空闲槽位。我们用装载因子(load factor)来表示空位的多少。

    散列表的装载因子=填入表中的元素个数/散列表的长度。装载因子越大,说明冲突越多,性能越差。

     

    3.什么是map?

    Map是一个集合,一种依照键(key)存储元素的容器,键(key)很像下标,在List中下标是整数。

    在Map中键(key)可以使任意类型的对象。Map中不能有重复的键(Key),每个键(key)都有一个对应的值(value)。

    一个键(key)和它对应的值构成map集合中的一个元素。

    Map中的元素是两个对象,一个对象作为键,一个对象作为值。键不可以重复,但是值可以重复。

    Map本身是一个接口,要使用Map需要通过子类进行对象实例化。

    Map接口的常用子类有:HashMap、HashTable、TreeMap、ConcurrentHashMap。

    (1)key值不允许重复,如果重复,则会把对应value值更新;

    (2)key和value都允许为null,key为null有且只有一个。

     

    4.什么是HashMap

    1.HashMap是一个用于存储Key-Value键值对的集合,每一个键值对也叫做Entry。

    这些个键值对(Entry)分散存储在一个数组当中,这个数组就是HashMap的主干。

    HashMap由数组+链表组成的,数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的,如果定位到的数组位置不含链表(当前entry的next指向null),那么查找,添加等操作很快,仅需一次寻址即可;如果定位到的数组包含链表,对于添加操作,其时间复杂度为O(n),首先遍历链表,存在即覆盖,否则新增;对于查找操作来讲,仍需遍历链表,然后通过key对象的equals方法逐一比对查找。所以,性能考虑,HashMap中的链表出现越少,性能才会越好。

     

    5.HashMap的实现原理或者工作原理?

    HashMap是基于hashing的原理,我们使用put(key, value)存储对象到HashMap中,使用get(key)从HashMap中获取对象。当我们给put()方法传递键和值时,我们先对键调用hashCode()方法,返回的hashCode用于找到bucket位置来储存Entry对象。

    (1)当获取对象时,通过键对象的equals()方法找到正确的键值对,然后返回值对象。HashMap使用链表来解决碰撞问题,当发生碰撞了,对象将会储存在链表的下一个节点中。 HashMap在每个链表节点中储存键值对对象。

    当两个不同的键对象的hashcode相同时会发生什么? 它们会储存在同一个bucket位置的链表中。键对象的equals()方法用来找到键值对。

    (2)当两个对象的hashcode相同会发生什么?

    答:因为hashcode相同,所以它们的bucket位置相同,‘碰撞’会发生。因为HashMap使用链表存储对象,这个Entry(包含有键值对的Map.Entry对象)会存储在链表中。”

    解析:虽然有很多种处理碰撞的方法,这种方法是最简单的,也正是HashMap的处理方法。

    (3)如果两个键的hashcode相同,你如何获取值对象?

    答:当我们调用get()方法,HashMap会使用键对象的hashcode找到bucket位置,找到bucket位置之后,会调用keys.equals()方法去找到链表中正确的节点,最终找到要找的值对象。

    解析:HashMap在链表中存储的是键值对

    (4)如果HashMap的大小超过了负载因子(load factor)定义的容量,怎么办?

    答:将会创建原来HashMap大小的两倍的bucket数组,来重新调整map的大小,并将原来的对象放入新的bucket数组中。

    解析:这个过程叫作rehashing,因为它调用hash方法找到新的bucket位置

    (5)你了解重新调整HashMap大小存在什么问题吗?

    答:当重新调整HashMap大小的时候,会存在条件竞争,因为如果两个线程都发现HashMap需要重新调整大小了,它们会同时试着调整大小。在调整大小的过程中,存储在链表中的元素的次序会反过来,因为移动到新的bucket位置的时候,HashMap并不会将元素放在链表的尾部,而是放在头部,这是为了避免尾部遍历(tail traversing)。如果条件竞争发生了,那么就死循环了。

    解析:跳出问题来看,为什么要在多线程的环境下使用HashMap呢?(多线程下不建议用HashMap)

    一句话总结就是,并发环境下HashMap的rehash过程可能会带来循环链表,导致死循环致使线程挂掉。

    因此并发环境下,建议使用Java.util.concurrent包中的ConcurrentHashMap以保证线程安全。

    至于HashTable,它并未使用分段锁,而是锁住整个数组,高并发环境下效率非常的低,会导致大量线程等待。

    同样的,Synchronized关键字、Lock性能都不如分段锁实现的

     

    5.HashMap安全吗?

    不安全,在多线程环境下,1.7 会产生死循环、数据丢失、数据覆盖的问题,1.8 中会有数据覆盖的问题,以1.8为例,

    当A线程判断index位置为空后正好挂起,B线程开始往index位置的写入节点数据,这时A线程恢复现场,执行赋值操作,就把A线程的数据给覆盖了;

    还有++size这个地方也会造成多线程同时扩容等问题。

     

    final V putVal(int hash, K key, V value, boolean onlyIfAbsent,

            boolean evict) {

            Node<K,V>[] tab; Node<K,V> p; int n, i;

            if ((tab = table) == null || (n = tab.length) == 0)

            n = (tab = resize()).length;

            if ((p = tab[i = (n - 1) & hash]) == null)  //多线程执行到这里

            tab[i] = newNode(hash, key, value, null);

            else {

            Node<K,V> e; K k;

            if (p.hash == hash &&

            ((k = p.key) == key || (key != null && key.equals(k))))

            e = p;

            else if (p instanceof TreeNode) // 这里很重要

            e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);

            else {

            for (int binCount = 0; ; ++binCount) {

            if ((e = p.next) == null) {

            p.next = newNode(hash, key, value, null);

            if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st

            treeifyBin(tab, hash);

            break;

            }

            if (e.hash == hash &&

            ((k = e.key) == key || (key != null && key.equals(k))))

            break;

            p = e;

            }

            }

            if (e != null) { // existing mapping for key

            V oldValue = e.value;

            if (!onlyIfAbsent || oldValue == null)

            e.value = value;

            afterNodeAccess(e);

            return oldValue;

            }

            }

            ++modCount;

            if (++size > threshold) // 多个线程走到这,可能重复resize()

            resize();

            afterNodeInsertion(evict);

            return null;

            }

     

  • 相关阅读:
    新浪微盘又是一个给力的产品啊,
    InfoQ: 百度数据库架构演变与设计
    列式数据库——Sybase IQ
    MapR初体验 淘宝共享数据平台 tbdata.org
    IBM正式发布新一代zEnterprise大型机(组图) 大型机,IBM,BladeCenter,美国,纽约 TechWeb News
    1TB is equal to the number of how many GB? 1PB equal to is equal to the number of TB? 1EB PB? | PCfault.com
    Cassandra vs HBase | WhyNosql
    The Hadoop Community Effect
    雅虎剥离开源软件平台 Hadoop ,与风投新建 Hortonworks 公司 品味雅虎
    RowOriented Database 、ColumnOriented Database 、KeyValue Store Database 、DocumentOriented Database
  • 原文地址:https://www.cnblogs.com/cdlyy/p/12584510.html
Copyright © 2011-2022 走看看