面试经验分享平台

将近几年的名企精品面试汇总、筛选、整理,再分享给大家
经验详情
2020年阿里春招+秋招+社招JAVA后端开发面试题总结(附答案)

前言

大家好,首先说一下这套题目是我朋友分享给我的,他作为阿里校招的面试官,分享一下他经常问的一些问题。目的是希望帮助参加校招的举一反三,当然也希望更多的同学能加入他的团队!


基于BIO实现的Server端, 当建立了100个连接时, 会有多少个线程?如果基于NIO, 又会是多少个线程?为什么?

通常来说基于NIO实现的Server端, 会用多少个线程去处理IO事件, 为什么?

c glib和Java的动态代理相比, 具体有什么不同?

用Executors.new Cached ThreadPool创建的线程池, 在运行的过程中有可能产生的风险是?

new ThreadPool Executor(10,100,10,Time Unit.MILLISECONDS,new Linked Blocking Queue(10) ) ; 一个这样创建的线程池,当已经有10个任务在运行时,第11个任务提交到此线程池执行的时候会发生什么,为什么?

除了用Object.wait和Object.notiyAll来实现线程间的交互外, 你还会常用哪些来实现?

为什么Concurrent HashMap可以在高并发的情况下比HashMap更为高效?

Atomic Integer、Atomic Boolean这些类之所以在高并发时高效, 共同的原因是?

请合理的使用Queue来实现一个高并发的生产/消费的场景, 给些核心的代码片段。

请实现让10个任务同时并发启动,给些代码片段。


在Java程序运行阶段, 可以用什么命令行工具来查看当前Java程序的一些启动参数值, 例如Heap Size等。

用什么命令行工具可以查看运行的Java程序的GC状况, 请具体写出命令行格式。

用什么工具, 可以在Java程序运行的情况下跟踪某个方法的执行时间, 请求参数信息等, 并请解释下工具实现的原理。

当一个Java程序接收请求, 很长时间都没响应的话, 通常你会怎么去排查这种问题?

Java进程突然消失了, 你会怎么去排查这种问题?

个别题个人的回答

BIO由于不是NIO那样的事件机制, 在连接的IO读取上, 无论是否真的有读/写发生, 都需要阻塞住当前的线程, 对于基于BIO实现的Server端, 通常的实现方法都是用一个线程去accept连接, 当连接建立后, 将这个连接的IO读写放到一个专门的处理线程, 所以当建立100个连接时, 通常会产生1个Accept线程+100个处理线程。


NIO通过事件来触发, 这样就可以实现在有需要读/写的时候才处理, 不用阻塞当前线程, NIO在处理IO的读写时,当从网卡缓冲区读或写入缓冲区时,这个过程是串行的,所以用太多线程处理IO事件其实也没什么意义,连接事件由于通常处理比较快, 用1个线程去处理就可以, IO事件呢, 通常会采用cpu core数+1或cpu core数*2, 这个的原因是IO线程通常除了从缓冲区读写外,还会做些比较轻量的例如解析协议头等,这些是可以并发的,为什么不只用1个线程处理, 是因为当并发的IO事件非常多时, 1个线程的效率不足以发挥出多core的CPU的能力, 从而导致这个地方成为瓶颈, 这种在分布式cache类型的场景里会比较明显, 按照这个, 也就更容易理解为什么在基于Netty等写程序时,不要在IO线程里直接做过多动作,而应该把这些动作转移到另外的线程池里去处理,就是为了能保持好IO事件能被高效处理。


从上面可以看出, 对于大多数需要建立大量连接, 但并发读写并不会同时的场景而言, NIO的优势是非常明显的。

这种关于BIO、NIO的问法的变化空间是非常大的, 还可以进一步拓展问问AIO和BIO、NIO的根本不同。


简单点讲是CGLIB可以代理类,这非常有助于像Spring AOP增强这样的场景的实现。


这题比较简单,主要是在考察对自带的这些线程池API的掌握能力,有没有在用的时候仔细的去了解,newCachedThreadPool最大的风险就是可能会创建超多的线程,导致最后不能创建线程。

这道题稍微拓展开下可以顺带问问创建100个线程会耗费多少资源,一个Java进程能创建多少线程池是受什么限制?


通常可以用jstat -gcutil [pid] [频率,例如多少毫秒一次] [多少次]来看目前的gc情况,如果已经打开了gc log,可以直接查看gc日志。

这种问题,稍微拓展下就可以看gc log通常怎么打开,具体的命令行参数,一段gc log的解读等。


btrace,Arthas,主要借助JVM attach agent,ASM以及Instrumentation来动态的替换字节码,从而实现动态的对程序运行情况的跟踪。


这题拓展开,可以问会有什么限制,这个可以进一步了解对原理的掌握程度,也可以请实际的讲一个借助这些工具排查的case,来看看实践情况。


双亲委派模型

双亲委派的意思是如果一个类加载器需要加载类,那么首先它会把这个类请求委派给父类加载器去完成,每一层都是如此。一直递归到顶层,当父加载器无法完成这个请求时,子类才会尝试去加载。


JDBC和双亲委派模型关系

因为类加载器受到加载范围的限制,在某些情况下父类加载器无法加载到需要的文件,这时候就需要委托子类加载器去加载class文件。


谈谈-synchronized和reentrantlock-的区别

首先synchronized是java内置关键字在jvm层面,Lock是个java类。


synchronized无法判断是否获取锁的状态,Lock可以判断是否获取到锁,并且可以主动尝试去获取锁。


synchronized会自动释放锁(a 线程执行完同步代码会释放锁 ;b 线程执行过程中发生异常会释放锁),Lock需在finally中手工释放锁(unlock()方法释放锁),否则容易造成线程死锁。


用synchronized关键字的两个线程1和线程2,如果当前线程1获得锁,线程2线程等待。如果线程1阻塞,线程2则会一直等待下去,而Lock锁就不一定会等待下去,如果尝试获取不到锁,线程可以不用一直等待就结束了。


synchronized的锁可重入、不可中断、非公平,而Lock锁可重入、可判断、可公平(两者皆可)


Lock锁适合大量同步的代码的同步问题,synchronized锁适合代码少量的同步问题。


核心线程池ThreadPoolExecutor的参数;

corePoolSize:指定了线程池中的线程数量。


maximumPoolSize:指定了线程池中的最大线程数量。


keepAliveTime:线程池维护线程所允许的空闲时间。


unit: keepAliveTime 的单位。


workQueue:任务队列,被提交但尚未被执行的任务。


threadFactory:线程工厂,用于创建线程,一般用默认的即可。


handler:拒绝策略。当任务太多来不及处理,如何拒绝任务。


ThreadPoolExecutor的工作流程

线程池的线程执行规则跟任务队列有很大的关系。



总结

最后说点鸡汤吧,在校招过程中心态真的很重要,我们可能会遇到简历挂、笔试挂、面试挂等各种各样的问题,一定要调整好心态,不要被网上一些贩卖焦虑的信息影响到,专心去提升自己,找准自己的定位和方向,然后不断坚持下去,一定会有所收获的。祝愿还没上岸的朋友们最终都能收获一份满意的工作!!!

————————————————

版权声明:本文摘录自网络,原文链接为:https://blog.csdn.net/weixin_53170315/article/details/111902833