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

一. 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)

二. 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语义

三. ContextClassLoader(线程上下文类加载器)的作用

越过类加载器的双亲委派机制去加载类,如serviceloader实现

使用线程上下文类加载器加载类,要注意保证多个需要通信的线程间的类加载器应该是同一个,防止因为不同的类加载器导致类型转换异常(ClassCastException)

四. tomcat 类加载机制

不同应用使用不同的 webapp类加载器,实现应用隔离的效果,webapp类加载器下面是jsp类加载器

不同应用共享的jar包可以放到Shared类加载器/shared目录下

五. 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. 否则,类查找失败

六. 如何结束一个一直运行的线程

使用退出标志,这个flag变量要多线程可见

使用interrupt,结合isInterrupted()使用

七. threadlocal使用场景及问题

threadlocal并不能解决多线程共享变量的问题,同一个 threadlocal所包含的对象,在不同的thread中有不同的副本,互不干扰

用于存放线程上下文变量,方便同一线程对变量的前后多次读取,如事务、数据库connection连接,在web编程中使用的更多

问题: 注意线程池场景使用threadlocal,因为实际变量值存放在了thread的threadlocalmap类型变量中,如果该值没有remove,也没有先set的话,可能会得到以前的旧值

问题: 注意线程池场景下的内存泄露,虽然threadlocal的get/set会清除key(key为threadlocal的弱引用,value是强引用,导致value不释放)为null的entry,但是最好remove

八. 线程池从启动到工作的流程

刚创建时,里面没有线程

调用 execute() 添加任务时:

  1. 如果正在运行的线程数量小于核心参数corePoolSize,继续创建线程运行这个任务
  2. 否则,如果正在运行的线程数量大于或等于corePoolSize,将任务加入到阻塞队列中
  3. 否则,如果队列已满,同时正在运行的线程数量小于核心参数maximumPoolSize,继续创建线程运行这个任务
  4. 否则,如果队列已满,同时正在运行的线程数量大于或等于 maximumPoolSize,根据设置的拒绝策略处理
  5. 完成一个任务,继续取下一个任务处理
  6. 没有任务继续处理,线程被中断或者线程池被关闭时,线程退出执行,如果线程池被关闭,线程结束
  7. 否则,判断线程池正在运行的线程数量是否大于核心线程数,如果是,线程结束,否则线程阻塞。因此线程池任务全部执行完成后,继续留存的线程池大小为corePoolSize

九. 阻塞队列BlockingQueue take和poll区别

poll(time):取走BlockingQueue里排在首位的对象,若不能立即取出,则可以等time参数规定的时间,取不到时返回null

take():取走BlockingQueue里排在首位的对象,若BlockingQueue为空,阻塞直到BlockingQueue有新的对象被加入

十. 如何从FutureTask不阻塞获取结果

get(long timeout,TimeUnit unit),超时则返回

轮询,先通过isDone()判断是否结束,然后调用get()

十一. blockingqueue如果存放了比较关键的数据,系统宕机该如何处理

开放性问题,欢迎讨论

将队列持久化,比较麻烦,需要将生产数据持久化到磁盘,持久化成功才返回,消费者线程从磁盘加载数据到内存阻塞队列中,维护消费offset,启动时,根据消费offset从磁盘加载数据

加入消息队列,保证消息不丢失,生成序列号,消费幂等,根据消费进程决定系统重启后的生产状态

十二. NIO与传统I/O的区别

节约线程,NIO由原来的每个线程都需要阻塞读写变成了由单线程(即Selector)负责处理多个channel注册(register)的兴趣事件(SelectionKey)集合(底层借助操作系统提供的epoll()),netty bossgroup处理accept连接(没看明白为什么bossgroup设置多个thread的必要性),workergroup处理具体业务流程和数据读写

NIO提供非阻塞操作

传统I/O 以流的方式处理数据,而 NIO 以块的方式处理数据,NIO提供bytebuffer,分为堆内和堆外缓冲区,读写时均先放到该缓冲区中,然后由内核通过channel传输到对端,堆外缓冲区不走内核,提升了性能

十三. list中存放可重复字符串,如何删除某个字符串

调用iterator相关方法删除

倒删,防止正序删除导致的数组重排,index跳过数组元素问题

十四. 有哪些GC ROOTS(跟日常开发比较相关的是和此相关的内存泄露)

所有Java线程当前活跃的栈帧里指向GC堆里的对象的引用,因此用不到的对象及时置null,提升内存回收效率

静态变量引用的对象,因此减少静态变量特别是静态集合变量的大小,集合存放的对象覆写euqls()和hashcode(),防止持续增长

本地方法JNI引用的对象

方法区中的常量引用的对象,因此减少在长字符串上调用String.intern()

classloader加载的class对象,因此自定义classloader无效时及时置null并且注意类加载器加载对象之间的隔离

jvm里的一些静态数据结构里指向GC堆里的对象的引用

写在最后:欢迎留言讨论,加关注,持续更新!!!

一线互联网常见的Java面试题,你颤抖了吗程序员的更多相关文章

  1. 一些常见的Java面试题 & 面试感悟

    < 前言 > 近期在面试,深感这个行业的浮躁,一些菜不辣基的弱鸡开出的工资待遇要求,超过了我.不知道他们是怎么拿到那么高的工资的,难道是他在公司有亲戚朋友吗?有后台吗?是行业热钱真的过多了 ...

  2. 最常见的Java面试题及答案汇总(三)

    上一篇:最常见的Java面试题及答案汇总(二) 多线程 35. 并行和并发有什么区别? 并行是指两个或者多个事件在同一时刻发生:而并发是指两个或多个事件在同一时间间隔发生. 并行是在不同实体上的多个事 ...

  3. 最常见的Java面试题及答案汇总(二)

    上一篇:最常见的Java面试题及答案汇总(一) 容器 18. java 容器都有哪些? 常用容器的图录: 19. Collection 和 Collections 有什么区别? java.util.C ...

  4. 互联网寒冬,阿里Ant Design还开坑,程序员该何去何从?

    金山都成立三十年了,不得不感叹中国在这三十年中,互联网确实是一步一步的在改变人们生活的方方面面,随着国家的发展,一大批企业搭上了互联网这趟高速列车走过了这几十年的风风雨雨,当然也造就了一批批传统行业无 ...

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

    跳槽不算频繁,但参加过不少面试(电话面试.face to face 面试),面过大 / 小公司.互联网 / 传统软件公司,面糊过(眼高手低,缺乏实战经验,挂掉),也面过人,所幸未因失败而气馁,在此过程 ...

  6. 208道最常见的Java面试题整理(面试必备)

    适宜阅读人群 需要面试的初/中/高级 java 程序员 想要查漏补缺的人 想要不断完善和扩充自己 java 技术栈的人 java 面试官 具体面试题 下面一起来看 208 道面试题,具体的内容. 一. ...

  7. 最常见的Java面试题及答案汇总(六)

    异常 74. throw 和 throws 的区别? throws是用来声明一个方法可能抛出的所有异常信息,throws是将异常声明但是不处理,而是将异常往上传,谁调用我就交给谁处理.而throw则是 ...

  8. 最常见的Java面试题及答案汇总(五)

    Java Web 64. jsp 和 servlet 有什么区别? jsp经编译后就变成了Servlet.(JSP的本质就是Servlet,JVM只能识别java的类,不能识别JSP的代码,Web容器 ...

  9. 编程漫谈(二十):如何自学编程及Java、上手真实开发及转行程序员的建议

    前路漫漫,吾将上下而求索! 最近有时在知乎上逛逛,发现很多人对自学编程及转行程序员有困惑.我是在25岁读研时转程序员,正赶上好时候(中国云计算刚刚起步及移动互联网正红的阶段),同时又走了不少弯路,因此 ...

随机推荐

  1. orcale11g安装

    一.centos7.5安装orcale 安装环境 内存最小1G,推荐2G或者更高 内存为1-2g,swap是内存的1.5倍左右 内存大于2G, swap和内存相等 硬盘最小为30G oracle版本 ...

  2. python面向对象之花里胡哨大杂烩

    python类的魔法方法之__str__.__repr__.__format__.__module__.__class__.__slots__.__call__.__del__(析构函数) 字符串的内 ...

  3. ELK之elasticsearch删除索引

    参考文档:https://www.cnblogs.com/Dev0ps/p/9493576.html elasticsearch使用时间久了会产生大量索引占用磁盘空间,可以删除索引来释放 查看当前所有 ...

  4. 使用ASP.NET Core支持GraphQL( restful 配套)

    https://github.com/graphql-dotnet https://github.com/graphql GraphQL简介 官网:https://graphql.cn/code/ 下 ...

  5. Vidual Studio vs2013彻底卸载

    我的win10 1803 2019年年中升级的,非常后悔,持续不间断的假死状态让人很无奈.又不舍得回退,因为很多保存的隐藏数据. 开始清理系统吧,东西越少性能越好,于是电脑就成了纯净版,甚至连 看到了 ...

  6. Mybatis映射文件sql语句注意事项

    1.插入

  7. 会话技术——Cookies和Session详解

    会话技术 (一) 概述.用途以及分类 (1) 基本概述 概述:会话是浏览器和服务器之间的多次请求和响应 也就是说,从浏览器访问服务器开始,到访问服务器结束,浏览器关闭为止的这段时间内容产生的多次请求和 ...

  8. Java:HashMap的实现原理(JDK1.8)

    1.    HashMap概述: HashMap是基于哈希表的Map接口的非同步实现.此实现提供所有可选的映射操作,并允许使用null值和null键.此类不保证映射的顺序,特别是它不保证该顺序恒久不变 ...

  9. Word 写论文插入参考文献的正确操作

    1. 引言 一般我们写论文插入参考文献的标号都是手动输入的,这样造成的问题有以下几个: 手动输入标号比较麻烦: 如果参考文献顺序变了,需要一个一个重新更改标号数值,及其麻烦: 标号无法和末尾的参考文献 ...

  10. ubuntu中不能使用终端的情况

    跟着网上的步骤去升级了一波python3,可谓一波未平! 当我将ubuntu中自带的python3.5升级3.6时,突然发现一个问题,怎么终端打不开了,于是去百度,找到一个博主的笔记,和我的情况一模一 ...