JAVA面经复习(十九)

面试难度:<mark>☆☆☆☆☆</mark>
声明:答案均为网上搜索汇总得到的参考答案,如有不妥或意见相左之处欢迎指出!

问:Redis底层的线程模型?

答:Redis基于Reactor模式开发了网络事件处理器,这个处理器被称为文件事件处理器。它的组成结构为4部分:多个套接字、IO多路复用程序、文件事件分派器、事件处理器。因为文件事件分派器队列的消费是单线程的,所以Redis才叫单线程模型。

问:zset集合底层数据结构,时间复杂度?

答:zset底层数据结构是字典+跳表。由于采用了跳表,因此时间复杂度是O(logn)。

问:aop?

答:面向切面编程,主要是将部分公用的业务代码抽象到一起,从而实现代码复用。底层采用动态代理实现的。动态代理又包括JDK自带的动态代理,和CGlib的一个动态代理,两种代理的区别主要在于JDK代理针对接口,而且采用的是反射获得对应的类代码,并调用对应的方法实现的。而CGlib动态代理则主要是通过ASM包加载代理对象的.class文件,并修改字节码获得对应的子类从而实现动态代理的。

问:springboot自动装配原理?

答:自动装配相关的几个注解主要是
1、@EnableAutoConfiguration,该注解开启对应容器的自动配置功能。
2、@Import(AutoConfigurationImportSelector),其是@EnableAutoConfiguration中的一个派生注解,其通过导入AutoConfigurationImportSelector的selectImports()方法扫描对应的所有具有META-INF/spring.factories的jar包,其中包含着所有的配置类,这些自动配置类又通过@EnableConfigurationProperties 注解支持通过xxxxProperties 读取application.properties/application.yml属性文件中我们配置的值。

问:springmvc?

答:springMVC是spring基础之上的一个MVC框架,主要处理web开发的路径映射和视图渲染,属于spring框架中WEB层开发的一部分,其主要分为Model(模型)、VIew(视图)、Controller(控制器)三部分,具体的工作流程如下。

问:mq了解吗?

答:消息队列,用与削峰,解耦合,减低服务器压力的一个中间件。

问:hashmap为什么用红黑树,为什么不用其他的树,为什么扩容是2倍,是否线程安全?

答:使用红黑树的原因是红黑树属于一种不严格意义上的平衡树,相比较严格意义上的平衡树,其维护和修改所需要的时间会较少。HashMap计算添加元素的位置时,使用的是位运算;另外,HashMap的初始容量是2的n次幂,扩容也是2倍的形式进行扩容,保持容量是2的n次幂,使得添加的元素均匀分布在HashMap中的数组上,减少hash碰撞,避免形成链表的结构。HashMap不是线程安全的,其在高并发下可能会出现数据覆盖和死循环的情况。

问:CurrentHashMap的put流程?

答:ConcurrentHashMap和HashMap的实现有很大的相似性,首先对对象调用hashCode()方法获获取值后在进行hash得到hash值,然后判断当前表是否初始化。
1、如果没有先进行初始化,根据hash计算得到的index判断当前点上是否有数据,没有直接放进数组。2、再判断当前是否在扩容,如果是在扩容则帮助扩容。
3、如果上述都不是,则加锁,锁住当前的Node节点(JDK1.8),随后判断是链表还是红黑树,如果是链表则遍历到链表尾部,不存在相同元素的话,则插入新节点,同时判断是否需要转换成红黑树。如果是红黑树,则查找红黑树,不存在相同节点则插入。
4、最后,插入数据后,判断是否需要扩容。

问:JMM?

答:JAVA内存模型,主要分为五个部分,堆,本地方法区,虚拟机栈,本地方法栈,程序计数器。其中,堆和本地方法区是线程共享的,程序计数器,虚拟机栈,本地方法栈是线程私有的。


2021年3月8日晚23:00重新修改:
上述问题答案有误,我错误的将运行时数据区域和JAVA内存模型搞混了,多谢评论的指正,如下是我重新修改整理的答案:


答:JMM隶属于JVM,是JVM中的一部分,从抽象的角度来看,JMM定义了线程和主内存之间的抽象关系:线程之间的共享变量存储在主内存(Main Memory)中,每个线程都有一个私有的本地内存(Local Memory),本地内存中存储了该线程以读/写共享变量的副本。本地内存是JMM的一个抽象概念,并不真实存在。它涵盖了缓存、写缓冲区、寄存器以及其他的硬件和编译器优化。

在JVM内部,Java内存模型把内存分成了两部分:线程栈区堆区
JVM中运行的每个线程都拥有自己的线程栈,线程栈包含了当前线程执行的方法调用相关信息,我们也把它称作调用栈。随着代码的不断执行,调用栈会不断变化。
堆区包含了Java应用创建的所有对象信息,不管对象是哪个线程创建的,其中的对象包括原始类型的封装类(如Byte、Integer、Long等等)。不管对象是属于一个成员变量还是方法中的局部变量,它都会被存储在堆区。

问:synchronize底层包括轻量级锁的实现,重量级锁、锁静态方法和非静态方法?

答:synchronize底层原理:在java语言中存在两种内建的synchronized语法:1、synchronized语句;2、synchronized方法。对于synchronized语句当Java源代码被javac编译成字节码的时候,会在同步块的入口位置和退出位置分别插入monitorenter和monitorexit字节码指令。而synchronized方法则会被翻译成普通的方法调用和返回指令如:invokevirtual、areturn指令,在VM字节码层面并没有任何特别的指令来实现被synchronized修饰的方法,而是在Class文件的方法表中将该方法的access_flags字段中的synchronized标志位置1,表示该方法是同步方法并使用调用该方法的对象或该方法所属的Class在JVM的内部对象表示Class做为锁对象。
轻量级别锁的实现:主要是借助于CAS的思想, 一个线程能够通过两种方式锁住一个对象:1、通过膨胀一个处于无锁状态(状态位001)的对象获得该对象的锁;2、对象已经处于膨胀状态(状态位00)但LockWord指向的monitor record的Owner字段为NULL,则可以直接通过CAS原子指令尝试将Owner设置为自己的标识来获得锁。(轻量级别的锁可以重入)
重量级锁:重量级别的锁和轻量级别的锁类似,只是在竞争失败后,不采用自旋的方式,而是直接阻塞。释放锁的时候唤醒对象。
锁静态/非静态方法:静态方法,需要对类对象加锁,该类对象可以是当前类也可以是一个类变量。非静态方法,需要对当前类对象(this)加锁。

问:aqs底层实现?

答:aqs即AbstractQueuedSynchronizer,它是一个同步工具也是 Lock 用来实现线程同步的核心组件。从使用层面来说,AQS 的功能分为两种:独占和共享。AQS 队列内部维护的是一个 FIFO 的双向链表,每个 Node 其实是由线程封装,当线程争抢锁失败后会封装成 Node 加入到 ASQ 队列中去;当获取锁的线程释放锁以后,会从队列中唤醒一个阻塞的节点(线程)。

问:线程池的生产线程的过程?

答:

问:osi七层模型,以及每层对应的内容?

答:物理层,数据链路层,网络层,传输层,会话层,表示层,应用层。具体内容如下。

问:jvm中几种引用类型?

答:强引用,默认引用为强引用。
软引用(SoftReference),是用来描述一些非必需但仍有用的对象。在内存足够的时候,软引用对象不会被回收,只有在内存不足时,系统则会回收软引用对象,如果回收了软引用对象之后仍然没有足够的内存,才会抛出内存溢出异常。这种特性常常被用来实现缓存技术,比如网页缓存,图片缓存等。
弱引用(WeakReference),其引用强度比软引用要更弱一些,无论内存是否足够,只要 JVM 开始进行垃圾回收,那些被弱引用关联的对象都会被回收。
虚引用( PhantomReference),是最弱的一种引用关系,如果一个对象仅持有虚引用,那么它就和没有任何引用一样,它随时可能会被回收,通过查看源码,发现它只有一个构造函数和一个 get() 方法,而且它的 get() 方法仅仅是返回一个null,也就是说将永远无法通过虚引用来获取对象,虚引用必须要和 ReferenceQueue 引用队列一起使用。

问:设置线程池(cpu密集/io密集),为什么cpu密集设置cpu核数+1而不是-1?

答:设置线程池的方法主要按照任务类型划分,最为主要的就是CPU密集型,IO密集型以及混合型任务。对于计算密集型(即CPU密集型)的程序,线程数应当大于等于核心数,因为再怎么计算密集,总有一些IO吧,所以再加一个线程来把等待IO的CPU时间利用起来。如果小于CPU核心数,那么CPU核心没办法被充分调用,那么任务效果就没有那么好了。

问:设计模式:适配,装饰,桥接,观察者模式?

答:适配器模式主要将当前提供的接口,通过转换,变换成用户希望的接口,有点想电器所使用的转换器。
装饰器模式,允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
桥接模式,是用于把抽象化与实现化解耦,使得二者可以独立变化。这种类型的设计模式属于结构型模式,它通过提供抽象化和实现化之间的桥接结构,来实现二者的解耦。
观察者模式,则主要是被观察者记录下观察者的信息,当被观察者出现消息响应或修改内容的时候,被观察者会主动发出消息给观察者,并使其做出相应的修改。
三言两语总也不能完整描述,还是建议看一看菜鸟教程的解析。

bean的生命周期?

答:

参考资料:
阿里淘系技术部校招Java一面面经
Spring Boot面试杀手锏————自动配置原理
HashMap初始容量为什么是2的n次幂及扩容为什么是2倍的形式
OSI七层模型与TCP/IP五层模型
Synchronize实现原理(很难)
线程池的工作原理详解(上)
线程池创建线程的过程
深究Spring中Bean的生命周期
JMM和底层实现原理