面试题day26
用友
2021年9月1日Java一面
-
Java有哪些集合,以及他们有哪些实现?
list map set
arraylist linkedlist hashmap treemap hashset treeset
-
HashMap底层实现,扩容了解吗?
- 扰动函数
(h = key.hashCode()) ^ (h >>> 16);
低16位与高16位做异或操作^,减少hash碰撞
- 扩容
- 链表引发
- 链表长度大于8,判断是否转为红黑树
- 数组大小大于64,转红黑树
- 数组大小小于64,扩容
- 链表长度大于8,判断是否转为红黑树
- 数组引发
- 数组元素大于容量与扩容因子之积,扩容
- 过程
- 每次扩容时都是将容量翻倍,即创建一个2倍大的新数组,然后再将旧数组中的数组迁移到新数组里。由于HashMap中数组的容量为2^N,所以可以用位移运算计算新容量,效率很高。在数据迁移时,为了兼顾性能,不会重新计算一遍每个key的哈希值,而是根据位移运算后(左移翻倍)多出来的最高位来决定,如果高位为0则元素位置不变,如果高位为1则元素的位置是在原位置基础上加上旧的容量。
- 链表引发
- 扰动函数
-
说一说ConcurrentHashMap
- 通过部分锁定+CAS算法来进行实现线程安全的
- put
- 先计算哈希值
- 再确定map是否初始化
- 插入数据
- 数组插入,cas
- 链表插入,先扩容,加锁
- 扩容
- 1.7
- 扩容时,对待扩容Segment内部会进行扩容,不影响其他Segment对象
- 扩容时,先生成新的数组,然后转移元素到新数组中
- 扩容的判断也是每个Segment内部单独判断的,判断是否超过阈值
- 1.8
- 如果某个线程put时,发现没有正在进行扩容,那么该线程一起进行扩容
- 如果某个线程put时,发现没有正在进行扩容,则将key-value添加到ConcurrentHashMap中, 然后判断是否超过阈值,超过了则进行扩容
- ConcurrentHashMap是支持多个线程同时扩容的。扩容前也是生成一个新数组,在转移元素时,先将原数组分组,将每组分给不同的线程来进行元素的转移,每个线程负责一组或多组的元素转移工作
- 1.7
-
synchronized加静态方法和成员方法上有什么区别?
锁对象不同
- 加锁方式
- 同步代码块(monitorenter和monitorexit)
- 同步方法(ACC_SYNCHRONIZED)
- 操作流程
- 首先会进入 EntryList 集合,当线程获取到对象的monitor后,进入 _Owner区域并把monitor中的owner变量设置为当前线程,同时monitor中的计数器count加1;
- 若线程调用 wait() 方法,将释放当前持有的monitor,owner变量恢复为null,count自减1,同时该线程进入 WaitSet集合中等待被唤醒;
- 若当前线程执行完毕,也将释放monitor(锁)并复位count的值,以便其他线程进入获取monitor(锁);
- 锁升级
- 锁消除
- Java虚拟机通过对运行上下文的扫描,经过逃逸分析,去除不可能存在竞争的锁,通过这种方式消除没有必要的锁,可以节省毫无意义的请求锁时间。实质是JIT编译器的同步省略或者叫同步消除
- 锁粗化
- 按理来说,同步块的作用范围应该尽可能小,但是加锁解锁也需要消耗资源,如果存在一系列的连续加锁解锁操作,可能会导致不必要的性能损耗。锁粗化就是将多个连续的加锁、解锁操作连接在一起,扩展成一个范围更大的锁,避免频繁的加锁解锁操作。
- 自适应自旋锁
- 如果在同一个锁对象上,自旋等待刚刚成功获得过锁,并且持有锁的线程正在运行中,那么虚拟机就会认为这次自旋也很有可能再次成功,进而允许自旋等待持续相对更长的时间。另一方面,如果对于某个锁,自旋很少成功获得过锁,那在以后要获取这个锁时将有可能直接省略掉自旋过程,以避免浪费处理器资源
- 加锁方式
-
sleep()和wait()有什么区别?
类、时机、释放锁
超时等待状态、等待状态
-
比如说有两个线程,有一个线程走到了synchronized方法里面了,另一个线程也掉入了这个synchronized方法,那么线程会怎么样?
锁碰撞、线程阻塞
-
线程池有哪些类型?
单线程池、定量线程池、动态线程池、定期线程池
-
如果线程池的线程满了的话,再往里面塞任务,会怎么做?它会再往哪个位置去存放这些东西?或者做一些其他处理?有什么一些策略?
核心线程数、阻塞队列、最大线程数、拒绝策略
直接抛出、抛出最早、抛异常(默认)、调用者执行
cpu密集型 n+1 io密集型 2n
-
CAS是什么概念?
原子操作、将预期值与旧值比较,成功更新为新值
aba问题、内存消耗、原子性
-
MySQL常用存储引擎
innodb、myisam
事务、锁、mvcc、外键、数据存储
-
事务隔离级别
ru rc rr s
脏读、不可重复读、幻读
-
如果要存放金额等带精度的数据,使用什么字段类型?
BigDecimal
-
分页用什么关键词?
SELECT * from user limit #{start},#{pageSize}
-
索引类型有哪些?
hash 数组 b+树
遍历层级短 io效率高
-
有没有看到过组合索引?
-
使用where时哪些语法尽量不要用?
索引失效
-
最左优先原则说一说
-
mybatis里面#{}与${}的区别,怎么理解预编译?为什么执行sql时要生成一个带?的sql?
预编译,提前占位
-
有没有看过框架的源码?
springmvc springboot
-
接触过哪些算法?
排序算法、搜索算法
-
Java内存管理
方法区 堆
直接内存 虚拟机栈 本地方法栈 程序计数器
清除 复制 压缩
分代假说
可达性算法 引用计数法
静态变量 常量 虚拟机栈 本地方法栈
-
redis有了解过吗?
-
redis的五大基本数据类型
- string 缓存 session共享 分布式锁
- list 消息队列
- hash 存储对象
- set 集合
- zset 排行榜
-
redis的两种持久化方式,redis的默认持久化方式
- aof 命令
- rdb 快照 默认
-
redis中的删除策略
- 定时删除
- 创建一个定时器,当key有过期时间时,时间一到,定时器任务就会立即执行 将expires区域和k-v区域都删除
- 优点:节约内存
- 缺点:cpu压力较大,此时无论cpu负载量多高,都会占用cpu来释放,影响redis的吞吐量
- 惰性删除
- 数据过期后,并不会立刻删除 等到该数据下次访问的时候,redis才会删除该数据,并返回该值为nil
- 优点:节省cpu的资源
- 缺点:可能存在大量的,无人访问的数据会一直存在服务器
- 定期删除
- 每秒钟定期对redis中每个库的数据进行轮询 轮询的数据,对过期的数据随机删除一部分 如果随机删除的数据占轮训数据的比例超过一定值,继续轮询删除
- 定时删除
-
-
微服务有接触过吗?
-
springboot和springMVC区别
配置