zoukankan      html  css  js  c++  java
  • Collection(list,set,map集合区别)。HashMap,ConcurrentHashMap原理。和CAS

    collection里面有什么子类?(list和set是实现了collection接口的。) 

    List:

    1.可以允许重复的对象(可重复,有序集合)。
    2.可以插入多个null元素。
    3.常用的实现类有 ArrayList、LinkedList 和 Vector。ArrayList 最为流行,而 LinkedList 则对于经常需要从 List 中添加或删除元素的场合更为合适。

    list去重:方法一:使用java8新特性stream进行List去重 。方法二:双重for循环去重 。方法三:set集合判断去重。方法四:遍历后判断赋给另一个list集合 。方法五:set和list转换去重

    List 的实现类有 ArrayList,Vector 和 LinkedList:

    ArrayList 和 Vector 内部是数组结构,线程不安全,在查询效率上会高很多。 Vector 是线程安全的,性能会稍慢一些。

    LinkedList:是双向链表的数据结构,在做查询时会按照序号索引数据进行前向或后向遍历,查询效率偏低,插入速度较快。

    Set:

    1.不允许重复对象(不可重复,无序集合)。
    2 只允许一个 null 元素
    3.Set 接口最流行的几个实现类是 HashSet、LinkedHashSet 以及 TreeSet。最流行的是基于 HashMap 实现的 HashSet;TreeSet 还实现了 SortedSet 接口,因此 TreeSet 是一个根据其 compare() 和 compareTo() 的定义进行排序的有序集合。而且可以重复。

    Set 的实现类有 HashSet 和 TreeSet:

    HashSet:内部是由哈希表(实际上是一个 HashMap 实例)支持的。集合元素可以是null,但只能放入一个null。无序的。

    TreeSet:是二叉树实现的,有序的,或者根据创建 set 时提供的 Comparator 进行排序。

    LinkedHashSet:是根据元素的hashCode值来决定元素的存储位置,但是它同时使用链表维护元素的次序。有序的,查询快,插入慢。当遍历该集合时候,LinkedHashSet将会以元素的添加顺序访问集合的元素。LinkedHashSet在迭代访问Set中的全部元素时,性能比HashSet好,但是插入时性能稍微逊色于HashSet。

    Map:

    1.Map不是collection的子接口或者实现类。Map是一个接口。
    2.不允许重复元素。
    3. Map 里你可以拥有随意个 null 值但只能有一个 null (key)键。
    4. Map 接口最流行的几个实现类是 HashMap、LinkedHashMap、Hashtable 和 TreeMap。(HashMap、TreeMap最常用)

    Map 的实现类有 HashMap,Hashtable、TreeMap和 LinkedHashMap:

    Hashtable:存储的键值对是无序的是按照哈希算法进行排序,与 HashMap 最大的区别就是线程安全(用synchronized)。键或者值不能为 null,为 null 就会抛出空指针异常。

    HashMap: 继承Map接口,实现了哈希表,允许null,线程不安全。哈希表结构其实就是数组+链表;在JDK1.8中规定:当链表长度大于8时,链表长度就转换为红黑树,大大                        提高了查找效率。

    TreeMap:基于红黑树 (二叉树) 数据结构实现,按 key 排序,默认的排序方式是升序。

    LinkedHashMap:有序的 Map 集合实现类,通过插入排序,相当于一个栈,先 put 进去的最后出来,先进后出。

    HashMap,Hashtable ,ConcurrentHashMap的区别?

    HashMap:  底层数据结构是哈希表,线程不安全,链表结构,效率高;

    Hashtable : 底层数据结构是哈希表,线程安全,但效率低,因为是Hashtable是使用synchronized的,所有线程竞争同一把锁;

    LinkedHashMap: 底层数据由哈希表+链表组成,由链表保证元素有序,哈希保证元素唯一,非线程安全

    Synchronized   Map: 线程安全,但效率低,一次性锁住整张表来保证线程安全,所以每次只能有一个线程来访问map。

    ConcurrentHashMap:线程安全而且效率高,因为它包含一个segment数组,将数据分段存储,给每一段数据配一把锁。

              在理想状态下,ConcurrentHashMap 可支持16个线程执行并发写操作,及任意数量线程的读操作。

    jdk1.7中采用Segment + HashEntry的方式进行实现。

    jdk1.8中放弃了Segment臃肿的设计,取而代之的是采用Node + CAS Synchronized来保证并发安全进行实现。(HashEntry在1.8中称为Node)

    Segment :  Segment 类继承于 ReentrantLock 类,从而使得 Segment 对象能充当锁的角色。

    HashEntry : 主要存储键值对,可以叫节点、用来封装散列映射表中的键值对。  https://blog.csdn.net/dfsaggsd/article/details/50572958

    如何线程安全的使用HashMap

      以下三种方式:用Hashtable、ConcurrentHashMap、或者Synchronized Map。

    Hashmap的数据结构是什么样子的?自己如何实现一个hashmap?

    主要数据结构即为数组+链表。默认长度是16。

    Hashmap的底层数据结构是由数组+链表组成的,是线程不安全,允许key和value为null。

    底层结构,数组叫哈希桶,而桶内则是链表,链表中的节点Node存放着实际的元素。

    HashMap底层(原理)是如何实现的?

      HashMap先得到key的散列值,在通过扰动函数(减少碰撞次数)得到Hash值,接着通过hash & (n -1 ),n位table的长度,运算后得到数组的索引值。如果当前节点存在元素,则通过比较hash值和key值是否相等,相等则替换,不相等则通过拉链法查找元素,直到找到相等或者下个节点为null时。

    HashMap是如何put元素的?

    HashMap在put方法中,调用内部方法putVal。它使用hashCode()和equals()方法。当我们通过传递key-value对调用put方法的时候,HashMap使用Key hashCode()和哈希算法来找出存储key-value对的索引。如果索引处为空,则直接插入到对应的数组中,否则哈希冲突,要判断是否是红黑树,若是,则红黑树插入,否则遍历链表,若长度超过8,则将链表转为红黑树,转成功之后 再插入。

    什么是Hash(哈希)、什么是Hash算法、什么是哈希表

      hash的定义:Hash译为散列,哈希是指一个过程,这个过程就是把任意长度的输入,通过散列算法,变换成固定长度的输出,所输出的称为哈希值(散列值)。

      Hash(哈希)算法:   即散列函数。它是一种单向密码体制,即它是一个从明文到密文的不可逆的映射,只有加密过程,没有解密过程。

      哈希表:   是根据设定的哈希函数(key)将一组关键字映射到一个有限的地址区间上,并以关键字在地址区间中的象作为记录在表中的存储位置,这种表称为哈希表或散列,所得存储位置称为哈希地址或散列地址。

    Hashmap的哈希怎么求出下标位置?

    1、进行哈希散列 hash();
          int h=key.hashCode();
    2、这里得到的是二进制数:比如:
          h=key.hashCode(); //得到的是32位二进制数

    3、转换成二进制后 >>>右移16位和hahsCode值进行位异或.

    4、然后index=(16-1)&&hash; 转换成二进制后index=2就是存储在数组中的下标位置。

    哈希碰撞(冲突)是什么,怎么解决? https://www.cnblogs.com/williamjie/p/9377028.html

      两个不同的原始值在经过哈希运算后得到同样的结果,这样就是哈希碰撞。
    解决方法:

    开放定址法:   原理是在HashMap中,把同样哈希值的位置以一串链表存储起来数据,把多个原始值不同而哈希结果相同的数据以链表存储起来。
    拉链法(链表法): 当发生地址冲突时,按照某种方法继续探测哈希表中的其他存储单元,直到找到空位置为止。

    在哈希法:   当发生冲突时,使用第二个、第三个、哈希函数计算地址,直到无冲突时。缺点:计算时间增加。

    谈一下hashMap中什么时候需要进行扩容,扩容resize()又是如何实现的?

    调用场景:

    1.当hashmap中的元素个数超过当前数组的长度 乘以 loadFactor(加载因子的值)时,就会进行数组扩容(loadFactor:默认值为0.75)

    扩容resize()实现过程:

    resize:原数组中的数据必须重新计算其在新数组中的位置,并放进去。

    1.通过判断旧数组的容量是否大于0来判断数组是否初始化过

    2、否:进行初始化。

    3、是,进行扩容,扩容成两倍(小于最大值的情况下),之后在进行将元素重新进行与运算复制到新的散列表中

    概括的讲:扩容需要重新分配一个新数组,新数组是老数组的2倍长,然后遍历整个老结构,把所有的元素挨个重新hash分配到新结构中去。

    JDK 1.7 HashMap扩容导致死循环的主要原因?
      HashMap扩容导致死循环的主要原因在于扩容后链表中的节点在新的hash桶使用头插法插入。(链表倒置以及链表过长。)

    新的hash桶会倒置原hash桶中的单链表,那么在多个线程同时扩容的情况下就可能导致产生一个存在闭环的单链表,从而导致死循环。

    JDK 1.8 HashMap扩容不会造成死循环的原因?

      使用的是尾插法,不会导致单链表的倒置,所以扩容的时候不会导致死循环。

    谈一下hashMap中get是如何实现的?

    对key的hashCode进行hashing,与运算计算下标获取bucket位置,如果在桶的首位上就可以找到就直接返回,否则在树中找或者链表中遍历找,如果有hash冲突,则利用equals方法去遍历链表查找节点。

    谈一下HashMap中hash函数是怎么实现的?还有哪些hash函数的实现方式?

    对key的hashCode做hash操作,与高16位做异或运算

    还有平方取中法,除留余数法,伪随机数法

    为什么不直接将key作为哈希值而是与高16位做异或运算?

      因为数组位置的确定用的是与运算,仅仅最后四位有效,设计者将key的哈希值与高16为做异或运算使得在做&运算确定数组的插入位置时,此时的低位实际是高位与低位的结合,增加了随机性,减少了哈希碰撞的次数。

    为什么是16?为什么必须是2的幂?如果输入值不是2的幂比如10会怎么样?

    https://blog.csdn.net/sidihuo/article/details/78489820

    https://blog.csdn.net/eaphyy/article/details/84386313

    1.为了数据的均匀分布,减少哈希碰撞。因为确定数组位置是用的位运算,若数据不是2的次幂则会增加哈希碰撞的次数和浪费数组空间。(PS:其实若不考虑效率,求余也可以就不用位运算了也不用长度必需为2的幂次)

    2.输入数据若不是2的幂,HashMap通过一通位移运算和或运算得到的肯定是2的幂次数,并且是离那个数最近的数字

    谈一下当两个对象的hashCode相等时会怎么样?

      会产生哈希碰撞,若key值相同则替换旧值,不然链接到链表后面,链表长度超过阙值8就转为红黑树存储

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

      HashCode相同,通过equals比较内容获取值对象

    1. java语言CAS底层如何实现?

      CAS是compare and swap的缩写,即我们所说的比较交换。cas是一种基于锁的操作,而且是乐观锁。

    通过某种方式不加锁来处理资源,比如通过给记录加version来获取数据,性能较悲观锁有很大的提高。

    具体:利用java(unsafe)提供的原子性操作方法。原子操作类,指的是java.util.concurrent.atomic包下,一系列以Atomic开头的包装类(AutoInteger)。

    2.什么事ABA问题?怎么解决?

      当一个值从A变成B,又更新回A,普通CAS机制会误判通过检测。

      利用加上version版本号比较可以有效解决ABA问题。每次跟新version+1。

  • 相关阅读:
    驾驶细节
    python 字符串前面加u,r,b,f的含义
    pandas dataframe指定列字符串转成数字的方法
    python 休息随机秒
    Windows搭建ffmpeg推流服务端 sky
    在golang中如何正确判断接口是否为nil
    快速了解一门技术的学习方法
    TortoiseGit使用教程(图文详细版)
    centos7升级安装openssl版本
    CentOS7防火墙,开放端口配置
  • 原文地址:https://www.cnblogs.com/lgg20/p/12324606.html
Copyright © 2011-2022 走看看