JDK1.7到JDK1.8 HashMap发生了什么变化(底层)
- 1.7中底层是数组 链表,1.8中底层是数组 链表 红黑树,加红黑树的目的是提高HashMap插入和查询整体效率
- 1.7中链表插入使用的是头插法,1.8中链表插入使用的是尾插法,因为1.8中插入key和value时需要判断链表元素个数,所以需要遍历链表统计链表元素个数,所以正好就直接使用尾插法
- 1.7中哈希算法比较复杂,存在各种右移与异或运算,1.8中进行了简化,因为复杂的哈希算法的目的就是提高散列性,来提供HashMap的整体效率,而1.8中新增了红黑树,所以可以适当的简化哈希算法,节省CPU资源
具体细节也可参考文章:对线面试官 - HashMap
JDK1.7到JDK1.8Java虚拟机发生了什么变化
1.7中存在永久代,1.8中没有永久代,替换它的是元空间,元空间所占的内存不是在虚拟机内部,而是本地内存空间,这么做的原因是,不管是永久代还是元空间,他们都是方法区的具体实现,之所以元空间所占的内存改成本地内存,官方的说法是为了和JRockit统一,不过额外还有一些原因,比如方法区所存储的类信息通常是比较难确定的,所以对于方法区的大小是比较难指定的,太小了容易出现方法区溢出,太大了又会占用了太多虚拟机的内存空间,而转移到本地内存后则不会影响虚拟机所占用的内存
- 细节部分可参考文章:
一问带你彻底了解JVM-Java内存区域详解
- 了解更多的JVM相关细节文章参考下列文章
JVM系列
如何实现AOP,项目哪些地方用到了AOP
利用动态代理技术来实现AOP,比如JDK动态代理或Cglib动态代理,利用动态代理技术,可以针对某个类生成代理对象,当调用代理对象的某个方法时,可以任意控制该方法的执行,比如可以先打印执行时间,再执行该方法,并且该方法执行完成后,再次打印执行时间。
项目中,比如事务、权限控制、方法执行时⻓日志都是通过AOP技术来实现的,凡是需要对某些方法做统一处理的都可以用AOP来实现,利用AOP可以做到业务无侵入。
Spring中后置处理器的作用
Spring中的后置处理器分为BeanFactory后置处理器和Bean后置处理器,它们是Spring底层源码架构设计中非常重要的一种机制,同时开发者也可以利用这两种后置处理器来进行扩展。BeanFactory后置处理器表示针对BeanFactory的处理器,Spring启动过程中,会先创建出BeanFactory实例,然后利用BeanFactory处理器来加工BeanFactory,比如Spring的扫描就是基于BeanFactory后置处理器来实现的,而Bean后置处理器也类似,Spring在创建一个Bean的过程中,首先会实例化得到一个对象,然后再利用Bean后置处理器来对该实例对象进行加工,比如我们常说的依赖注入就是基于一个Bean后置处理器来实现的,通过该Bean后置处理器来给实例对象中加了@Autowired注解的属性自动赋值,还比如我们常说的AOP,也是利用一个Bean后置处理器来实现的,基于原实例对象,判断是否需要进行AOP,如果需要,那么就基于原实例对象进行动态代理,生成一个代理对象。
如图所示
说说常用的SpringBoot注解,及其实现
- @SpringBootApplication注解:这个注解标识了一个SpringBoot工程,它实际上是另外三个注解的组合,这三个注解是:
- @SpringBootConfiguration:这个注解实际就是一个@Configuration,表示启动类也是一个配置类
- @EnableAutoConfiguration:向Spring容器中导入了一个Selector,用来加载ClassPath下SpringFactories中所定义的自动配置类,将这些自动加载为配置Bean
- @ComponentScan:标识扫描路径,因为默认是没有配置实际扫描路径,所以SpringBoot扫描的路径是启动类所在的当前目录
- @Bean注解:用来定义Bean,类似于XML中的标签,Spring在启动时,会对加了@Bean注解的方法进行解析,将方法的名字做为beanName,并通过执行方法得到bean对象
- @Controller、@Service、@ResponseBody、@Autowired都可以说
具体细节不做过多赘述。
说说你了解的分布式锁实现
分布式锁所要解决的问题的本质是:能够对分布在多台机器中的线程对共享资源的互斥访问。在这个原理上可以有很多的实现方式:
- 基于Mysql,分布式环境中的线程连接同一个数据库,利用数据库中的行锁来达到互斥访问,但是MySQL的加锁和释放锁的性能会比较低,不适合真正的实际生产环境
- 基于Zookeeper,Zookeeper中的数据是存在内存的,所以相对于Mysql性能上是适合实际环境的,并且基于Zookeeper的顺序节点、临时节点、Watch机制能非常好的来实现的分布式锁
- 基于Redis,Redis中的数据也是在内存,基于Redis的消费订阅功能、数据超时时间,lua脚本等功能,也能很好的实现的分布式锁
Redis的数据结构及使用场景
Redis提供了三种集群策略:
- 主从模式:这种模式比较简单,主库可以读写,并且会和从库进行数据同步,这种模式下,客户端直接连主库或某个从库,但是但主库或从库宕机后,客户端需要手动修改IP,另外,这种模式也比较难进行扩容,整个集群所能存储的数据受到某台机器的内存容量,所以不可能支持特大数据量
- 哨兵模式:这种模式在主从的基础上新增了哨兵节点,但主库节点宕机后,哨兵会发现主库节点宕机,然后在从库中选择一个库作为进的主库,另外哨兵也可以做集群,从而可以保证但某一个哨兵节点宕机后,还有其他哨兵节点可以继续工作,这种模式可以比较好的保证Redis集群的高可用,但是仍然不能很好的解决Redis的容量上限问题。
- Cluster模式:Cluster模式是用得比较多的模式,它支持多主多从,这种模式会按照key进行槽位的分配,可以使得不同的key分散到不同的主节点上,利用这种模式可以使得整个集群支持更大的数据容量,同时每个主节点可以拥有自己的多个从节点,如果该主节点宕机,会从它的从节点中选举一个新的主节点
对于这三种模式,如果Redis要存的数据量不大,可以选择哨兵模式,如果Redis要存的数据量大,并且需要持续的扩容,那么选择Cluster模式。
MySQL数据库中,什么情况下设置了索引但无法使用
- 没有符合最左前缀原则
- 字段进行了隐式数据类型转化
- 走索引没有全表扫描效率高
MySQL索引设计原则可以参考文章:MySQL索引设计原则
Innodb是如何实现事务的
Innodb通过Buffer Pool,LogBuffer,Redo Log,Undo Log来实现事务,以一个update语句为例:
- Innodb在收到一个update语句后,会先根据条件找到数据所在的⻚,并将该⻚缓存在Buffer Pool中
- 执行update语句,修改Buffer Pool中的数据,也就是内存中的数据
- 针对update语句生成一个RedoLog对象,并存入LogBuffer中
- 针对update语句生成undolog日志,用于事务回滚
- 如果事务提交,那么则把RedoLog对象进行持久化,后续还有其他机制将Buffer Pool中所修改的数据⻚持久化到磁盘中
- 如果事务回滚,则利用undolog日志进行回滚
发散性思考题
聊聊你最有成就的
- 项目是做什么的
- 用了什么技术
- 你在项目中担任的职位
自己最有挑战的项目、
- 使用什么技术解决了什么项目难点
- 使用什么技术优化了什么项目功能
- 使用什么技术节省了多少成本
好了本章到此结束,希望对你有所帮助,注学习顺利
注:文中的图片可能略有不清晰,但是尽力了,如果有小伙伴有什么好的建议,欢迎留言谢谢