互联网大厂java面试题一美团

1、Spring AOP 底层原理

aop 底层是采用动态代理机制实现的:接口+实现类

*如果要代理的对象,实现了某个接口,那么 Spring AOP 会使用 JDK Proxy,去创建代

理对象。

*没有实现接口的对象,就无法使用 JDK Proxy 去进行代理了,这时候 Spring AOP 会

使用 Cglib 生成一个被代理对象的子类来作为代理。

就是由代理创建出一个和 imp*实现类平级的一个对象,但是这个对象不是一个真正的对象,

只是一个代理对象,但它可以实现和 imp*相同的功能,这个就是 aop 的横向机制原理,这

样就不需要修改源代码。

2、HashMap 的底层数据结构是怎样的 ?

JDK1.8 之前

*JDK1.8 之前 HashMap 底层是 数组和链表 结合在一起使用也就是 链表散列。

*HashMap 通过 key 的 hashCode 经过扰动函数处理过后得到 hash 值,然后通过

(n -1) & hash 判断当前元素存放的位置(这里的 n 指的是数组的长度),如果当前位置存在

元素的话,就判断该元素与要存入的元素的 hash 值以及 key 是否相同,如果相同的话,

直接覆盖,不相同就通过拉链法解决冲突。

*所谓扰动函数指的就是 HashMap 的 hash 方法。使用 hash 方法也就是扰动函数是为了

防止一些实现比较差的 hashCode() 方法 换句话说使用扰动函数之后可以减少碰撞。

JDK1.8 之后

当链表长度大于阈值(默认为 8)时,会首先调用 treeifyBin()方法。这个方法会根据

HashMap 数组来决定是否转换为红黑树。只有当数组长度大于或者等于 64 的情况下,才会

执行转换红黑树操作,以减少搜索时间。否则,就是只是执行 resize() 方法对数组扩容。

3、HashMap 的扩容机制是怎样的?

一般情况下,当元素数量超过阈值时便会触发扩容。每次扩容的容量都是之前容量的 2 倍。

HashMap 的容量是有上限的,必须小于 1<<30,即 1073741824。如果容量超出了这个

数,则不再增长,且阈值会被设置为 Integer.MAX_VALUE。

JDK7 中的扩容机制

*空参数的构造函数:以默认容量、默认负载因子、默认阈值初始化数组。内部数组是空数

组。

*有参构造函数:根据参数确定容量、负载因子、阈值等。

*第一次 put 时会初始化数组,其容量变为不小于指定容量的 2 的幂数,然后根据负载因

子确定阈值。

*如果不是第一次扩容,则 新容量=旧容量 x 2 ,新阈值=新容量 x 负载因子 。

JDK8 的扩容机制

*空参数的构造函数:实例化的 HashMap 默认内部数组是 null,即没有实例化。第一次

调用 put 方法时,则会开始第一次初始化扩容,长度为 16。

*有参构造函数:用于指定容量。会根据指定的正整数找到不小于指定容量的 2 的幂数,

将这个数设置赋值给阈值(threshold)。第一次调用 put 方法时,会将阈值赋值给容量,

然后让 阈值 = 容量 x 负载因子。

*如果不是第一次扩容,则容量变为原来的 2 倍,阈值也变为原来的 2 倍。(容量和阈值

都变为原来的 2 倍时,负载因子还是不变)。

此外还有几个细节需要注意:

*首次 put 时,先会触发扩容(算是初始化),然后存入数据,然后判断是否需要扩容;

*不是首次 put,则不再初始化,直接存入数据,然后判断是否需要扩容;

4、ConcurrentHashMap 的存储结构是怎样的?

*Java7 中 ConcurrnetHashMap 使用的分段锁,也就是每一个 Segment 上同时只有一

个线程可以操作,每一个 Segment 都是一个类似 HashMap 数组的结构,它可以扩容,

它的冲突会转化为链表。但是 Segment 的个数一但初始化就不能改变,默认 Segment

的个数是 16 个。

*Java8 中的 ConcurrnetHashMap 使用的 Synchronized 锁加 CAS (Compare and Swap,即比较再交换)的机制。结构也由Java7 中的 Segment 数组 + HashEntry 数组 + 链表 进化成了 Node 数组 + 链表 / 红黑树,Node 是类似于一个 HashEntry 的结构。它的冲突再达到一定大小时会转化成红黑树,在冲突小于一定数量时又退回链表。

5、线程池大小如何设置?

*CPU 密集型任务(N+1): 这种任务消耗的主要是 CPU 资源,可以将线程数设置为 N

(CPU 核心数)+1,比 CPU 核心数多出来的一个线程是为了防止线程偶发的缺页中断,

或者其它原因导致的任务暂停而带来的影响。一旦任务暂停,CPU 就会处于空闲状态,

而在这种情况下多出来的一个线程就可以充分利用 CPU 的空闲时间。

*I/O 密集型任务(2N): 这种任务应用起来,系统会用大部分的时间来处理 I/O 交互,而线

程在处理 I/O 的时间段内不会占用 CPU 来处理,这时就可以将 CPU 交出给其它线程使

用。因此在 I/O 密集型任务的应用中,我们可以多配置一些线程,具体的计算方法是 2N。

如何判断是 CPU 密集任务还是 IO 密集任务?

CPU 密集型简单理解就是利用 CPU 计算能力的任务,比

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值