【春招实习】贝壳金服电话一面:
面试过程及内容:
-
自我介绍
建议这块在电话面试的时候准备一份自己的简历,方便在自我介绍的时候挑出重点,能够比较快速和流畅的介绍自己。
-
Java有几种基本类型,int和float类型各占几个字节?
Java中总共有八种数据类型:byte(1)、short(2)、int(4)、long(8)、char(2)、float(4)、double(8)和boolean;
PS: 括号内的为各个类型所占的字节数。
-
Java集合:HashMap是否会存在线程安全问题,如何解决?
HashMap可能会出现的线程安全问题的地方:
- HashMap中插入数据:假设正好存在两个 put 的 key 发生了碰撞(根据 hash 值计算的 bucket 一样)的线程A、B,然后对同一个数组位置调用createEntry方法,两个线程都会同时得到头结点,然后A写入新的头结点之后,B也写入新的头结点,那B的写入操作就会覆盖A的写入操作造成A的写入操作丢失。
- HashMap扩容的时候:
- 如果多个线程同时检测到元素个数超过数组大小 ,这样就会发生多个线程同时对 Node 数组进行扩容,都在重新计算元素位置以及复制数据,但是最终只有一个线程扩容后的数组会赋给 table,也就是说其他线程的都会丢失,并且各自线程 put 的数据也丢失。
- HashMap 在并发执行 put 操作时会引起死循环,导致 CPU 利用率接近100%。因为多线程会导致 HashMap 的 Node 链表形成环形数据结构,一旦形成环形数据结构,Node 的 next 节点永远不为空,就会在获取 Node 时产生死循环。
如何安全的使用HashMap?
- Hashtable
- ConcurrentHashMap
- Collections.synchronizedMap(new HashMap(…));
-
Map,Array,list三者的区别和共同点,以及时间复杂度?(其实我觉得当时的面试官应该是想问我:Map,Set和list三者的区别?)
当时自己就着重回答了Arraylist和linkedlist的区别:
- 实现的不同:ArrayList是实现了基于动态数组的数据结构,而LinkedList是基于链表的数据结构;
- 访问速度的不同:随机访问get和set,ArrayList要优于LinkedList,因为LinkedList要移动指针;
- 插入删除速度的不同:一般都认为LinkedList要比ArrayList快,但是这仅适用于从随机位置插入(因为数组从中间插入,需要移动元素),当从尾部插入数据时,插入的数据量很小时,两者区别不太大,当插入的数据量大时,大约在容量的1/10之前,LinkedList会优于ArrayList,在其后就劣与ArrayList,且越靠近后面越差。
Map,Set和list三者的区别:
- list:其中的值允许重复,因为其为有序的数据结构 ,允许空值
- 三个实现类:LinkedList、ArrayList、Vector
- set :其中的值不允许重复,无序的数据结构 (Set 集合根据 hashcode 来进行数据的存储,所以位置是固定的,但是位置不是用户可以控制的,所以对于用户来说 set 中的元素还是无序的)
- 两个实现类:TreeSet 、HashSet
- map:成对的数据结构,健值必须具有唯一性(键不能同,否则值替换)
- 四个实现类:HashMap、HashTable、SortMap、 LinkedHashMap
-
Abstract(抽象类)和interface(接口)的区别?
不同点:
- 抽象类中可以有构造方法,接口中不能;
- 抽象类中可以有普通成员变量,接口中不能;
- 抽象类中可以包含普通方法,接口中不能;
- 抽象类中的访问权限是:public、protect,接口中只能是 public;
- 抽象类中可以包含静态方法,接口中不能;
- 抽象类中可以包含任意类型的静态成员变量,接口中只能是public static final;
- 一个类只能继承一个类,但是可以继承多个接口;
相同点:
- 不能够实例化
- 可以将抽象类和接口类型作为引用类型
- 一个类如果继承了某个抽象类或者实现了某个接口都需要对其中的抽象方法全部进行实现,否则该类仍然需要被声明为抽象类
-
Http、TCP/IP的区别与关系?
TPC/IP协议是传输层协议,主要解决数据如何在网络中传输,而HTTP是应用层协议,主要解决如何包装数据。
自己补充说了一下有关https的东西,https大致的请求过程如图
-
MySQL多表查询、索引以及索引的底层实现
这部分大概就举了一个实际的例子进行分析,然后说了下索引的使用条件,以及底层实现所用的B树和B+树
-
Java线程状态有多少种?以及各个状态之间如何转化?
-
新建(new):新创建了一个线程对象。
-
就绪(runnable):线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取cpu 的使用权 。
-
运行(running):可运行状态(runnable)的线程获得了cpu 时间片(timeslice) ,执行程序代码。
-
阻塞(block):阻塞状态是指线程因为某种原因放弃了cpu 使用权,也即让出了cpu timeslice,暂时停止运行。直到线程进入可运行(runnable)状态,才有机会再次获得cpu timeslice 转到运行(running)状态。阻塞的情况分三种:
- 等待阻塞:运行(running)的线程执行o.wait()方法,JVM会把该线程放入等待队列(waitting queue)中。
- 同步阻塞:运行(running)的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池(lock pool)中。
- 其他阻塞:运行(running)的线程执行Thread.sleep(long ms)或t.join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入可运行(runnable)状态。
-
死亡(dead):线程run()、main() 方法执行结束,或者因异常退出了run()方法,则该线程结束生命周期。死亡的线程不可再次复生。
-
用过Redis的原子操作吗?
其实刚听到这个问题还是有点蒙的,下来查了之后觉得应该是指Redis中的原子锁:
- INCR: key不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作进行加一。 然后其它用户在执行 INCR 操作进行加一时,如果返回的数大于 1 ,说明这个锁正在被使用当中。
- SETNX:这种加锁的思路是,如果 key 不存在,将 key 设置为 value 如果 key 已存在,则
SETNX
不做任何动作 - getSet:获取key的旧值,将新value放入
-
Redis 3.0 以后单机和集群的特性?
听到这个问题的时候,真的留下了不学无术的泪水,自己就胡扯了一下主从复制、哨兵以及单机瓶颈的原因。
Redis集群的特点:
- 所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽.
- 节点的fail是通过集群中超过半数的节点检测失效时才生效.
- 客户端与redis节点直连,不需要中间proxy层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可
- redis-cluster把所有的物理节点映射到[0-16383]slot(插槽)上,cluster 负责维护node<->slot<->value
总结
这次面试算是自己第一次进行电话技术面试,所以很紧张,很多问题都出现了答非所问的情况。总体感觉这次面试的难度一般,更加侧重于基础知识,只有最后两个问题可能会稍微困难一点。以及前期可能复习侧重点的问题,可能忽略了对于基础知识的弥补,也算是对于自己的一个提醒吧。