美团/链家面试真题

-1)ArrayList和LinkedList,如果一直在list的尾部添加元素,用哪个效率高?

当输入的数据一直是小于千万级别的时候,大部分是LinkedList效率高,而当数据量大于千万级别的时候,就会出现ArrayList的效率比较高了。为什么呢?

原来 LinkedList每次增加的时候,会new 一个Node对象来存新增加的元素,所以当数据量小的时候,这个时间并不明显,而ArrayList需要扩容,所以LinkedList的效率就会比较高,其中如果ArrayList出现不需要扩容的时候,那么ArrayList的效率应该是比LinkedList高的,当数据量很大的时候,new对象的时间大于扩容的时间,那么就会出现ArrayList的效率比LinkedList高了
 

1)介绍一下TCP的三次握?如果去掉最后一次握手会怎样?(客户端等待服务端ack number ,服务端等待客户端ack number)

如果此时ACK在网络中丢失,那么Server端该TCP连接的状态为SYN_RECV,并且依次等待3秒、6秒、12秒后重新发送SYN+ACK包,以便Client重新发送ACK包。 Server重发SYN+ACK包的次数,可以通过设置/proc/sys/net/ipv4/tcp_synack_retries修改,默认值为5。 如果重发指定次数后,仍然未收到ACK应答,那么一段时间后,Server自动关闭这个连接。 但是Client认为这个连接已经建立,如果Client端向Server写数据,Server端将以RST包(用于强制关闭tcp连接)响应,方能感知到Server的错误。

  1. 画一下HashMap底层结构

  2. 数据结构中有数组和链表来实现对数据的存储,但这两者基本上是两个极端。

          数组

    数组存储区间是连续的,占用内存严重,故空间复杂的很大。但数组的二分查找时间复杂度小,为O(1);数组的特点是:寻址容易,插入和删除困难;

    链表

    链表存储区间离散,占用内存比较宽松,故空间复杂度很小,但时间复杂度很大,达O(N)。链表的特点是:寻址困难,插入和删除容易。

    哈希表

    那么我们能不能综合两者的特性,做出一种寻址容易,插入删除也容易的数据结构?答案是肯定的,这就是我们要提起的哈希表。哈希表((Hash table)既满足了数据的查找方便,同时不占用太多的内容空间,使用也十分方便。

      哈希表有多种不同的实现方法,我接下来解释的是最常用的一种方法—— 拉链法,我们可以理解为“链表的数组” ,如图:

     

     

      从上图我们可以发现哈希表是由数组+链表组成的,

  3. HashMap是线程安全的吗,那怎么才能线程安全? ConcurrentHashMap原理

  4. 我认为主要可以通过以下三种方法来实现:

    1.替换成Hashtable,Hashtable通过对整个表上锁实现线程安全,因此效率比较低

    2.使用Collections类的synchronizedMap方法包装一下。方法如下:

    public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m)  返回由指定映射支持的同步(线程安全的)映射

    3.使用ConcurrentHashMap,它使用分段锁来保证线程安全

    通过前两种方式获得的线程安全的HashMap在读写数据的时候会对整个容器上锁,而ConcurrentHashMap并不需要对整个容器上锁,它只需要锁住要修改的部分就行了

  5. 众所周知,哈希表是中非常高效,复杂度为O(1)的数据结构,在Java开发中,我们最常见到最频繁使用的就是HashMap和HashTable,但是在线程竞争激烈的并发场景中使用都不够合理。

      HashMap :先说HashMap,HashMap是线程不安全的,在并发环境下,可能会形成环状链表(扩容时可能造成,具体原因自行百度google或查看源码分析),导致get操作时,cpu空转,所以,在并发环境中使用HashMap是非常危险的。

      HashTable : HashTable和HashMap的实现原理几乎一样,差别无非是1.HashTable不允许key和value为null;2.HashTable是线程安全的。但是HashTable线程安全的策略实现代价却太大了,简单粗暴,get/put所有相关操作都是synchronized的,这相当于给整个哈希表加了一把大锁,多线程访问时候,只要有一个线程访问或操作该对象,那其他线程只能阻塞,相当于将所有的操作串行化,在竞争激烈的并发场景中性能就会非常差。

      HashTable性能差主要是由于所有操作需要竞争同一把锁,而如果容器中有多把锁,每一把锁锁一段数据,这样在多线程访问时不同段的数据时,就不会存在锁竞争了,这样便可以有效地提高并发效率。这就是ConcurrentHashMap所采用的"分段锁"思想。

      

  6. 如果hashMap的key是一个自定义的类,怎么办
  7. key的自定义类重写hashcode和equals方法,且这两个方法的返回值必须保持一致,即hashcode值相等则equals返回true
  8. 1.hashmap的内部实现

    答:hashmap 是对数据结构hash table 的内部实现,哈希表也叫散列表,有着不错的查询和添加速度。它通过关键吗key来访问其对应的值value。就是关键码key(key.hashcode())的映射函数来找到表中相对应的位置的value。它结合了链表和数组的优势,其中链表是用来解决hash冲突的。其链接节点数据结构是entry<k,v>,每个entry对象内部又含有指向下一个对象entry的引用。(hashmap 扩容后的长度总是为2的次幂)

    2.如果hashMap的key是一个自定义的类,how?

    答:需要重写hashcode()和equals()方法。因为不重写的话,entry里面的其他内部属性会影响hashcode的值,明明相等的两个对象可能会判断不相等。

    3.为什么重写equals还要重写hashcode?

    答:因为hashmap在判断两个对象相等的时候,会先使用key.hashcode来找到相对应的位置,因此如果不重写hashcode的话,hashcode 会受到entry内部其他属性的影响,导致发生错误。

    4.ArrayList和LinkedList的区别,如果一直在list的尾部添加元素,用哪个效率高?

    答:ArrayList的底层数据结构是数组,linkedList的底层数据结构为链表。通常Arraylist的查询速度快于LinkedList,LinkedList的插入删除速度快于ArrayList。 但是一直在尾部添加元素的话,ArrayList快于LinkedList.

    5.介绍一下Syncronized锁。如果用这个关键字修饰一个静态方法,锁住了什么?如果修饰成员方法,锁住了什么

    答:Syncronized锁是同步锁,如果关键字修饰静态方法的话是一个类锁(当前类的所有线程都必须等待同步线程执行), 如果关键字修饰成员方法的话是一个对象锁(当前对象的所有线程必须等待同步线程执行完,释放锁)。

    6.介绍一下volatile

    答:volatile关键字可以修饰共享变量。保证其他线程访问这个变量的时候始终是最新值 也就是volatile会更新最新值到内java主内存中去,其他线程使用这个变量的时候会从java主内存中去取得这个变量。(解决可见性和有序性)

    7.多线程中的i++线程安全吗?为什么

    答:是不安全的,因为每个线程都会分配到自己的工作内存,i也会在执行的时候被暂时保存到工作内存中,所以如果当其他线程调用i的时候无法调用到i最新的值。所以这里要使用volatile关键字。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值