APP下载

一线互联网常见的 14 个 Java 面试题 程序员的你颤抖了吗?

消息来源:baojiabao.com 作者: 发布时间:2026-05-27

报价宝综合消息一线互联网常见的 14 个 Java 面试题 程序员的你颤抖了吗?

跳槽不算频繁,但参加过不少面试(电话面试、face to face 面试),面过大 / 小公司、互联网 / 传统软件公司,面糊过(眼高手低,缺乏实战经验,挂掉),也面过人,所幸未因失败而气馁,在此过程中不断查缺补漏,养成了踏实、追本溯源、持续改进的习惯,特此将自己经历过、构思过的一些面试题记录下来,如果答案有问题,欢迎拍砖讨论,希望能对找工作或者感兴趣的同学有所帮助,陆续整理中。1. synchronized 和 reentrantlock 异同

相同点

都实现了多执行绪同步和内存可见性语义都是可重入锁不同点

实现机制不同 synchronized 通过 java 物件头锁标记和 Monitor 物件实现 reentrantlock 通过CAS、ASQ(AbstractQueuedSynchronizer)和 locksupport(用于阻塞和解除阻塞)实现synchronized 依赖 jvm 内存模型保证包含共享变数的多执行绪内存可见性 reentrantlock 通过 ASQ 的volatile state 保证包含共享变数的多执行绪内存可见性使用方式不同 synchronized 可以修饰例项方法(锁住例项物件)、静态方法(锁住类物件)、程式码块(显示指定锁物件)reentrantlock 显示呼叫 trylock/lock 方法,需要在 finally 块中释放锁功能丰富程度不同 reentrantlock提供有限时间等候锁(设定过期时间)、可中断锁(lockInterruptibly)、condition(提供 await、signal等方法)等丰富语义 reentrantlock 提供公平锁和非公平锁实现 synchronized不可设定等待时间、不可被中断(interrupted)2. concurrenthashmap 为何读不用加锁

jdk1.7

1)HashEntry 中的 key、hash、next 均为 final 型,只能表头插入、删除结点2)HashEntry 类的 value 域被宣告为 volatile 型3)不允许用 null 作为键和值,当读执行绪读到某个 HashEntry 的 value 域的值为 null时,便知道产生了冲突——发生了重排序现象(put 设定新 value 物件的字节码指令重排序),需要加锁后重新读入这个 value 值4)volatile 变数 count 协调读写执行绪之间的内存可见性,写操作后修改 count,读操作先读 count,根据happen-before 传递性原则写操作的修改读操作能够看到jdk1.8

1)Node 的 val 和 next 均为 volatile 型2)tabAt 和 casTabAt 对应的 unsafe 操作实现了 volatile 语义3. ContextClassLoader(执行绪上下文类载入器)的作用

越过类载入器的双亲委派机制去载入类,如 serviceloader 实现使用执行绪上下文类载入器载入类,要注意保证多个需要通讯的执行绪间的类载入器应该是同一个,防止因为不同的类载入器导致型别转换异常(ClassCastException)4. tomcat 类载入机制

不同应用使用不同的 webapp 类载入器,实现应用隔离的效果,webapp 类载入器下面是 jsp 类载入器不同应用共享的 jar 包可以放到 Shared 类载入器 /shared 目录下5. osgi 类载入机制

osgi 类载入模型是网状的,可以在模组(Bundle)间互相委托osgi 实现模组化热部署的关键是自定义类载入器机制的实现,每个 Bundle 都有一个自己的类载入器,当需要更换一个 Bundle时,就把 Bundle 连同类载入器一起换掉以实现程式码的热替换当收到类载入请求时,osgi 将按照下面的顺序进行类搜寻:

1)将以 java.* 开头的类委派给父类载入器载入2)否则,将委派列表名单(配置档案 org.osgi.framework.bootdelegation 中定义)内的类委派给父类载入器载入3)否则,检查是否在 Import-Package 中宣告,如果是,则委派给 Export 这个类的 Bundle 的类载入器载入4)否则,检查是否在 Require-Bundle 中宣告,如果是,则将类载入请求委托给 required bundle 的类载入器5)否则,查询当前 Bundle 的 ClassPath,使用自己的类载入器载入6)否则,查询类是否在自己的 Fragment Bundle 中,如果在,则委派给 Fragment Bundle 的类载入器载入7)否则,查询 Dynamic Import-Package(Dynamic Import 只有在真正用到此 Package的时候才进行载入)的 Bundle,委派给对应 Bundle 的类载入器载入8)否则,类查询失败6. 如何结束一个一直执行的执行绪

使用退出标志,这个 flag 变数要多执行绪可见使用 interrupt,结合 isInterrupted 使用7. threadlocal 使用场景及问题

threadlocal 并不能解决多执行绪共享变数的问题,同一个 threadlocal 所包含的物件,在不同的 thread中有不同的副本,互不干扰用于存放执行绪上下文变数,方便同一执行绪对变数的前后多次读取,如事务、数据库 connection 连线,在 web 程式设计中使用的更多问题: 注意执行绪池场景使用 threadlocal,因为实际变数值存放在了 thread 的 threadlocalmap型别变数中,如果该值没有 remove,也没有先 set 的话,可能会得到以前的旧值问题: 注意执行绪池场景下的内存泄露,虽然 threadlocal 的 get/set 会清除 key(key 为 threadlocal的弱引用,value 是强引用,导致 value 不释放)为 null 的 entry,但是最好 remove8. 执行绪池从启动到工作的流程

刚建立时,里面没有执行绪

呼叫 execute 新增任务时:

1)如果正在执行的执行绪数量小于核心引数 corePoolSize,继续建立执行绪执行这个任务2)否则,如果正在执行的执行绪数量大于或等于 corePoolSize,将任务加入到阻塞伫列中3)否则,如果伫列已满,同时正在执行的执行绪数量小于核心引数 maximumPoolSize,继续建立执行绪执行这个任务4)否则,如果伫列已满,同时正在执行的执行绪数量大于或等于 maximumPoolSize,根据设定的拒绝策略处理5)完成一个任务,继续取下一个任务处理6)没有任务继续处理,执行绪被中断或者执行绪池被关闭时,执行绪退出执行,如果执行绪池被关闭,执行绪结束7)否则,判断执行绪池正在执行的执行绪数量是否大于核心执行绪数,如果是,执行绪结束,否则执行绪阻塞。因此执行绪池任务全部执行完成后,继续留存的执行绪池大小为corePoolSize8)本文所列出的 14 个 Java面试题只是我所遭遇的面试中的一部分,其他的面试题我也会陆续整理出来,说到这里另外顺便给大家推荐一个架构交流学习群:650385180,里面会分享一些资深架构师录制的视讯录影:有Spring,MyBatis,Netty 源代码分析,高并发、高效能、分散式、微服务架构的原理,JVM效能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,相信对于已经工作和遇到技术瓶颈的码友,在这个群里会有你需要的内容。9. 阻塞伫列 BlockingQueue take 和 poll 区别

poll(time):取走 BlockingQueue 里排在首位的物件, 若不能立即取出,则可以等 time引数规定的时间,取不到时返回 nulltake:取走 BlockingQueue 里排在首位的物件,若 BlockingQueue 为空,阻塞直到BlockingQueue 有新的物件被加入10. 如何从 FutureTask 不阻塞获取结果

get(long timeout,TimeUnit unit),超时则返回轮询,先通过 isDone判断是否结束,然后呼叫 get11. blockingqueue 如果存放了比较关键的资料,系统宕机该如何处理

开放性问题,欢迎讨论将伫列持久化,比较麻烦,需要将生产资料持久化到磁盘,持久化成功才返回,消费者执行绪从磁盘载入资料到内存阻塞伫列中,维护消费offset,启动时,根据消费 offset 从磁盘载入资料加入讯息伫列,保证讯息不丢失,生成序列号,消费幂等,根据消费程序决定系统重启后的生产状态12. NIO 与传统 I/O 的区别

节约执行绪,NIO 由原来的每个执行绪都需要阻塞读写变成了由单执行绪(即 Selector)负责处理多个 channel注册(register)的兴趣事件(SelectionKey)集合(底层借助操作系统提供的 epoll),netty bossgroup 处理 accept 连线(没看明白为什么 bossgroup 设定多个 thread的必要性),workergroup 处理具体业务流程和资料读写NIO 提供非阻塞操作传统 I/O 以流的方式处理资料,而 NIO 以块的方式处理资料,NIO 提供 bytebuffer,分为堆内和堆外缓冲区,读写时均先放到该缓冲区中,然后由核心通过 channel传输到对端,堆外缓冲区不走核心,提升了效能13. list 中存放可重复字串,如何删除某个字串

呼叫 iterator 相关方法删除倒删,防止正序删除导致的阵列重排,index 跳过阵列元素问题14. 有哪些 GC ROOTS(跟日常开发比较相关的是和此相关的内存泄露)

所有 Java 执行绪当前活跃的栈帧里指向 GC 堆里的物件的引用,因此用不到的物件及时置 null,提升内存回收效率静态变数引用的物件,因此减少静态变数特别是静态集合变数的大小,集合存放的物件覆写 euqls和 hashcode,防止持续增长本地方法 JNI 引用的物件方法区中的常量引用的物件,因此减少在长字串上呼叫 String.internclassloader 载入的 class 物件,因此自定义 classloader 无效时及时置 null并且注意类载入器载入物件之间的隔离jvm 里的一些静态资料结构里指向 GC 堆里的物件的引用…更多面试大型互联网面试题,下次我们再来分享!

欢迎工作一到五年的Java工程师朋友们加入Java高阶架构:617912068

进群领取面试资料了解互联网最新的面试题,为到来的2019做准备!

群内提供免费的Java架构学习资料(里面有高可用、高并发、高效能及分散式、Jvm效能调优、Spring源代码,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多个知识点的架构资料)合理利用自己每一分每一秒的时间来学习提升自己,不要再用"没有时间“来掩饰自己思想上的懒惰!趁年轻,使劲拼,给未来的自己一个交代

2019-01-21 07:38:00

相关文章