-
请你说说ArrayList和LinkedList的区别
- ArrayList底层是数组实现的,数组是一组连续的内存单元,读取快(使用索引),插入删除慢(需要重新计算大小或是更新索引)
- LinkedList底层基于双向链表,读取慢,插入删除快;链表的每一个节点保存了数据值,和指向前一个节点的指针和指向后一个节点的指针。占内存
-
请你说说聚簇索引和非聚簇索引
- 两者主要的区别是数据和索引的分离,聚簇不分离,非聚簇分离
- 非聚簇索引是除了聚簇索引的其他索引,可以采用非主键作为索引
-
数据库为什么不用红黑树而用B+树?
- 索引的存储会存储在磁盘中,每次查询都要到磁盘中访问,对于红黑树,树的高度非常高,会进行多次磁盘IO,效率非常低
- B+树的高度一般为2-4,也就是说在最坏的条件下,也就最多进行2-4次IO,这在实际中性能非常不错
-
请你讲讲工厂模式,手写实现工厂模式
- 工厂模式:不暴露创建对象的具体逻辑,而是将逻辑封装在一个函数中,那么这个函数就被视为一个工厂
- 具有简单工厂,工厂方法,抽线工厂
-
你知道哪些线程安全的集合?
- Vector,hashTable线程安全,基于Synchronized关键字实现线程安全
- ArrayList、LinkList、HashMap线程不安全
- ConcurrentHashMap是线程并发集合类中的安全HashMap
-
请你说说ConcurrentHashMap
- ConcurrentHashMap底层数据结构与HashMap一样,也是采用“数组+链表+红黑树”
- 采用了锁定头节点的方式降低了锁粒度,以较低的性能代价实现了线程安全
- 实现机制:
- 初始化数组头节点时,ConcurrentHashMap并没有加锁,而是CAS的方式进行原子性替换
- 插入数据时会进行加锁处理,但锁定的不是整个数组,而是槽中的头节点,所以ConcurrentHashMap的锁的粒度是槽,而不是整个数组,并发的性能很好
- 扩容时会进行加锁处理,锁定的仍然是头节点,并且支持多个线程同时对数组扩容,提高并发能力
- 在扩容过程中,依然可以支持查找操作
-
说说缓存穿透、击穿、雪崩的区别
- 缓存穿透:客户端访问的数据不存在,使得请求直接访问存储层,导致负载过大,宕机
- 原因:业务层误删了缓存和库中的数据,或是有人恶意访问不存在的数据
- 解决方式:存储层未命中后,返回空值存入缓存层,客户端再次访问时,缓存层直接返回空值;将数据存入布隆过滤器,访问缓存之前经过过滤器拦截,若请求的数据不存在则直接返回空值
- 缓存击穿:一份热点数据,它的访问量非常大,它的缓存失效的瞬间,大量请求直达存储层,导致服务崩溃
- 解决方式:永不过期,对热点数据不设置过期时间;加互斥锁,当一个线程访问该数据时,另一个线程只能等待,这个线程访问之后,缓存中的数据都将被重建,届时其他线程就可以从缓存中取值
- 缓存雪崩:大量数据同时过期、或是redis节点故障导致服务不可用,缓存层无法提供服务,所有请求直达缓存层,造成数据库宕机
- 解决方式:避免数据同时过期,设置随机过期时间;启用降级和熔断措施;设置热点数据永不过期;采用redis集群,一个宕机,另外的还能用。
-
Redis如何与数据库保持双写一致性
- 先更新数据库再更新缓存。缺点:多线程情况下会存在数据库中的数据和缓存中的数据不一致的情况
- 先更新缓存再更新数据库。每次数据变换都可以及时更新缓存,但消耗大,影响服务器性能
- 先删除缓存再更新数据库。也会导致缓存和数据库中数据不一致
- 先更新数据库再删除缓存。也会存在数据库和缓存数据不一致,但可以使用重试机制,最好的解决方案
-
说说你了解的线程同步方式
- Java通过加锁实现线程同步,锁有两类:synchronized和Lock。
- synchronized加在3个不同位置的地方,对应3种不同的使用方式,这三种区别是锁对象不同
- 加在普通方法上,则锁是当前实例
- 加在静态方法上,则锁是当前class对象
- 加在代码块上,则需要在关键字后面的小括号里,显式指定一个对象为锁对象
- lock支持的功能包括:支持响应中断、支持,超时机制,支持以非阻塞的方式获取锁、支持多个条件变量
-
请你说说innodb和myisam的区别?
- 事务是否支持:innodb支持事务,而myisam不支持事务
- 锁粒度:innodb是行级锁,myisam是表级锁
- 读写性能:innodb是增删改性能优,myisam是查询性能优
-
String、StringBuffer、Stringbuilder有什么区别?
- String:不可变字符串,效率低,但复用率高
- StringBuffer:可变字符串,效率较高(增删),线程安全
- StringBuilder:可变字符串,效率最高,线程不安全
-
请你说说HashMap底层原理
- JDK1.8之前是数组+链表,之后就是数组+链表+红黑树
- put流程:基于哈希算法来确定元素位置,当我们向集合存入数据时,他会计算传入key的哈希值,并利用哈希值计算得到元素的位置,如果这个位置存在数据,则会发生哈希碰撞
- 当某个元素位置的链表长度大于等于8的时候转化为红黑树,从而提高查询速度
- 扩容机制:HashMap中数组的默认初始化容量为16,当默认负载因子达到0.75时,会以2的指数倍扩容
- HashMap是非线程安全,在多线程环境下会产生循环死链,多线程环境下使用ConcurrentHashMap