
这两天的面试能约就约,因为马上就是周末了基本上没公司上班,今天约了两场,上午和下午。
我遇到不会的答不上来,或者答出来不是很满意,就很紧张然后磕磕绊绊的,得多面试见识不同的面试官练练胆子,然后看看面试中级程序员主要问哪些问题,
面试过程
上午场的面试:
上午的面试比较无厘头,提的问题我基本能答上来,最后问我还需要了解一些什么?最后就说让我回去等消息,然后软件上说我不通过…问他原因也不说,不过还是总结一下他的问题。
- 线程的创建方式
- 线程的几种状态
- 线程池几种策略
- 为什么要三次握手
- Redis 几种类型
- JVM内存模型
- JVM如何调优
- 你还需要了解一些什么?
下午场的面试:
下午的面试体验还可以,但问了几个八股文我答不上来应该是没过,这个公司面试的人比较多,要先填表,HR 还会倒杯水喝,映像很不错比昨天放松一些。我前面那个哥们进去不到 5 分钟就出来了,下一个是我。但面试官看起来比较和善,自我介绍后,问了一些学校、然后工作的项目经历,谈了大概快 20 多分钟整体上还不错挺轻松的,但随之就问八股文了,丫的,问的这些八股文太抽象了,我是一个答不上来,虽然我看到过这种题目但是真没去记这些东西,但是我也说了很多自己的理解,把我知道的都说了,很显然是不标准的,然后开始紧张了…类似于空气凝固了,面试官估计也懂,问我哪时候开始准备面试的,我说昨天才开始面试。
- SpringBean 生命周期
- JVM 垃圾回收的几种算法
面试总结
线程的创建方式
我觉得满意的回答(点击展开)
四种:- 继承 Thread 类
- 实现 RunAble 接口
- 实现 CallAble 接口
- 线程池
要是只说这四种也太逊了,我觉得得知道哪些时候用哪种,或者说应用场景优劣势。
继承 Thread 类
- 优点:能直接调用 Thread 类的方法,如 getName,其他实现的接口得用 Thread.currentThread才行
- 缺点:因为 Java 是单继承多实现的,拓展性差。
实现 RunAble 接口
- 优点:拓展性高,一个类可以实现多个接口,而且比1方法写法简单,匿名内部类只需写方法的实现即可。
- 缺点:不能直接调用 Thread 类的方法
使用 Callable 和 Future
- 优点:可以接受返回值
- 缺点:相对复杂?性能问题,要创建Future 对象,有一点点开销。
1 | private static void extracted() { |
- Executors 接口实现线程池
- 优点:高效,面对使用对象简单
- 缺点:管理和维护较为复杂
1 | public static void main(String[] args){ |
上午场的面试:
线程的几种状态
我觉得满意的回答(点击展开)
- 新建 new Thread()
- 就绪 start() 跟cpu抢夺资源
- 运行 实际在跑
- 阻塞 线程被锁
- 等待 wait(),join(),sleep(),sleep(argument),join(arg),wait(arg)
- 终止
线程池几种策略
我觉得满意的回答(点击展开)
当线程池和任务队列都满时,线程池会拒绝新任务。常见的拒绝策略包括:
- AbortPolicy 抛出 RejectedExecutionException 异常,默认策略。
- CallerRunsPolicy 由调用线程处理该任务。
- DiscardPolicy 直接丢弃任务,不抛出异常
- DiscardOldestPolicy 丢弃队列中最旧的任务,并尝试重新提交新任务。
为什么要三次握手
三次握手是为了确保双方都能正常接收和发送数据,防止已失效的连接请求报文段被服务端接收,造成错误。
- 第一次握手:客户端发送连接请求报文段,等待服务端确认。
- 第二次握手:服务端收到请求后,发送同意连接的确认报文段。
- 第三次握手:客户端收到确认后,再次向服务端发送确认报文段,连接建立。
Redis 几种类型
27号有总结
JVM内存模型
比较抽象是以下这几种
- 堆(Heap)
- 栈(Stack):
- 方法区(Method Area)
- 本地方法栈(Native Method Stack):主要是native,比如 hashcode 这种
- 程序计数器(Program Counter, PC):存储当前执行指令的地址
JVM如何调优
- 垃圾回收器(Garbage Collection)
- 触发GC
- 内存分配调优、JVM 参数调优
- 比如IDEA 内存太小,用指令-Xms1024m -Xmx2048m
- -Xss 设置线程栈大小
你还需要了解一些什么?
这是一道拓展题,一般答得还行几乎都会留给自己发挥,等会总结一下
下午场的面试:
SpringBean 生命周期
JVM 垃圾回收的几种算法
标记-清除算法(Mark-Sweep)
标记阶段:从根节点(如栈和静态变量)开始遍历,对所有可达对象进行标记。
清除阶段:遍历整个堆,对没有标记的对象进行回收。
优点:简单、直接。 缺点:内存碎片化严重,影响性能。复制算法(Copying)
复制算法将堆分为两个相等的区域,每次只使用其中一个。当内存用尽时,将存活的对象复制到另一个区域,并清空当前区域。
优点:高效,避免内存碎片。
缺点:需要双倍的内存空间。标记-整理算法(Mark-Compact)
这种算法结合了标记-清除和复制算法的优点:
标记阶段:标记所有可达对象。
整理阶段:将存活对象移动到堆的一端,按顺序排列,最后清理掉非存活对象。
优点:避免内存碎片。 缺点:对象移动成本高。
- 分代收集算法(Generational Collection)
- 循环依赖怎么解决
- 构造器注入:不支持循环依赖。
- Setter 注入:Spring 通过三级缓存解决循环依赖。
- 一级缓存:存放完全初始化好的 Bean。
- 二级缓存:存放早期暴露的 Bean(未完成初始化)。
- 三级缓存:存放 Bean 工厂对象,用于解决循环依赖。