跳槽不算频繁,但参加过不少面试(电话面试、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,但是最好 remove
8. 线程池从启动到工作的流程
- 刚创建时,里面没有线程
- 调用 execute() 添加任务时:
- 1)如果正在运行的线程数量小于核心参数 corePoolSize,继续创建线程运行这个任务
- 2)否则,如果正在运行的线程数量大于或等于 corePoolSize,将任务加入到阻塞队列中
- 3)否则,如果队列已满,同时正在运行的线程数量小于核心参数 maximumPoolSize,继续创建线程运行这个任务
- 4)否则,如果队列已满,同时正在运行的线程数量大于或等于 maximumPoolSize,根据设置的拒绝策略处理
- 5)完成一个任务,继续取下一个任务处理
- 6)没有任务继续处理,线程被中断或者线程池被关闭时,线程退出执行,如果线程池被关闭,线程结束
- 7)否则,判断线程池正在运行的线程数量是否大于核心线程数,如果是,线程结束,否则线程阻塞。因此线程池任务全部执行完成后,继续留存的线程池大小为 corePoolSize
- 8)本文所列出的 14 个 Java 面试题只是我所遭遇的面试中的一部分,其他的面试题我也会陆续整理出来,说到这里另外顺便给大家推荐一个架构交流学习群:650385180,里面会分享一些资深架构师录制的视频录像:有 Spring,MyBatis,Netty 源码分析,高并发、高性能、分布式、微服务架构的原理,JVM 性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,相信对于已经工作和遇到技术瓶颈的码友,在这个群里会有你需要的内容。
9. 阻塞队列 BlockingQueue take 和 poll 区别
- poll(time):取走 BlockingQueue 里排在首位的对象, 若不能立即取出,则可以等 time 参数规定的时间,取不到时返回 null
- take():取走 BlockingQueue 里排在首位的对象,若 BlockingQueue 为空,阻塞直到 BlockingQueue 有新的对象被加入
10. 如何从 FutureTask 不阻塞获取结果
- get(long timeout,TimeUnit unit),超时则返回
- 轮询,先通过 isDone()判断是否结束,然后调用 get()
11. 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.intern()
- classloader 加载的 class 对象,因此自定义 classloader 无效时及时置 null 并且注意类加载器加载对象之间的隔离
- jvm 里的一些静态数据结构里指向 GC 堆里的对象的引用
- …
一线互联网常见的 14 个 Java 面试题,你颤抖了吗程序员的更多相关文章
-
一线互联网常见的14个Java面试题,你颤抖了吗程序员
跳槽不算频繁,但参加过不少面试(电话面试.face to face面试),面过大/小公司.互联网/传统软件公司,面糊过(眼高手低,缺乏实战经验,挂掉),也面过人,所幸未因失败而气馁,在此过程中不断查缺 ...
-
一线互联网企业常见的14个Java面试题,Java面试题集大全等你拿,颤抖吧程序员!
本文由尚学堂学员们根据自己参加过的面试回忆.总结而成,一线互联网企业常见的14个Java面试题,包括各大互联网企业.创业小公司,互联网企业.传统软件公司.对于刚毕业和想要跳槽的宝宝们,再适用不过啦,赶 ...
-
(转)大厂常问到的14个Java面试题
1. synchronized和reentrantlock异同 相同点 都实现了多线程同步和内存可见性语义 都是可重入锁 不同点 实现机制不同 synchronized通过java对象头锁标记和Mon ...
-
Java实现批量下载《神秘的程序员》漫画
上周看了西乔的博客“西乔的九卦”.<神秘的程序员们>系列漫画感觉很喜欢,很搞笑.这些漫画经常出现在CSDN“程序员”杂志末页的,以前也看过一些. 后来就想下载下来,但是一张一张的点击右键“ ...
-
编程漫谈(二十):如何自学编程及Java、上手真实开发及转行程序员的建议
前路漫漫,吾将上下而求索! 最近有时在知乎上逛逛,发现很多人对自学编程及转行程序员有困惑.我是在25岁读研时转程序员,正赶上好时候(中国云计算刚刚起步及移动互联网正红的阶段),同时又走了不少弯路,因此 ...
-
Java学习路线图&#183;影响一代又一代程序员的经典书籍!(转)
转自:http://www.douban.com/group/topic/50353428/ 基础篇 ·Java核心技术 卷1 基础知识(原书第9版)最新版·中文版 第13届Jolt生产效率大奖获奖图 ...
-
学Java的前景与就业,资深程序员教你怎么开始学Java!
IT行业一直是就业的热门岗位,程序员这个职业稳定性和收入比都有着不错的前景,那么学Java的前景和就业是什么样的呢?随着入行Java的准程序员越来越多,各种学习Java的流派也层出不穷!其实在编程的世 ...
-
程序员职业规划(一篇来自";阿里Java工程师";对工作3年左右程序员的职业建议和应该掌握的职业技能)
程序员的三个阶段(转载) 第一阶段:三年 我认为三年对于程序员来说是第一个门槛,这个阶段将会淘汰掉一批不适合写代码的人. 这一阶段,我们走出校园,迈入社会,成为一名程序员,正式从书本上的内容迈向真正的 ...
-
一线互联网常见的Java面试题,你颤抖了吗程序员
跳槽不算频繁,但参加过不少面试(电话面试.face to face面试),面过大/小公司.互联网/传统软件公司,面糊过(眼高手低,缺乏实战经验,挂掉),也面过人,所幸未因失败而气馁,在此过程中不断查缺 ...
随机推荐
-
jQuery美女幻灯相册轮播源代码
体验效果:http://hovertree.com/texiao/jquery/ 本幻灯片包含小图列表和大图轮播,包含图片标题和详细介绍,详细介绍字数可以很多,每张图片包含链接,可以实现跳转 HTML ...
-
WPF DatePicker默认显示当前日期
WPF的日历选择控件默认为当前日期,共有两种方法,一种静态,一种动态. 静态的当然写在DatePicker控件的属性里了,动态的写在对应的cs文件里,具体请看下面. 1.方法一: my ...
-
MyEclipse for Spring启动时报错";An internal error occurred during: &#39;Updating indexes&#39;.Java heap space";的解决办法
问题 MyEclipse for Spring在启动时,报如下错误:An internal error occurred during: 'Updating indexes'.Java heap sp ...
-
linux安装apache的纠结过程
本以为linux下安装apache是件很简单的过程.三命令就可以搞定,jxvf解压,make 编译,make install 安装就OK了.没想到这个过程还颇费周折.可能和环境有关吧.先说一下我的环境 ...
-
这样就算会了PHP么?-8
关于PHP的一些时间函数,这个小节完之后,就可以进入PHP比较高级的内容啦... <?php date_default_timezone_set("Asia/Shanghai" ...
-
Eclipse、maven项目常见问题
阿里云maven仓库地址: <mirror> <id>nexus-aliyun</id> <mirrorOf>*</mirrorOf> &l ...
-
html5 postMessage解决跨域、跨窗口消息传递[转载]
原文:http://www.cnblogs.com/dolphinX/p/3464056.html 一些麻烦事儿 平时做web开发的时候关于消息传递,除了客户端与服务器传值还有几个经常会遇到的问题 1 ...
-
OpenCV——老照片效果
// define head function #ifndef PS_ALGORITHM_H_INCLUDED #define PS_ALGORITHM_H_INCLUDED #include < ...
-
IO流(三)
五.Java序列化 概述 Java序列化是指把Java对象转换为字节序列的过程 Java反序列化是指把字节序列恢复为Java对象的过程 当两个Java进程进行通信时,发送方需要把这个Java对象转换为 ...
-
unzip解压带密码的压缩包
// 解压 String pw = "123456"; String cmd = "unzip -P " + pw + " /root/lianlia ...