程序员社区

java面试常见问题大全!准备春招面试必看!

目录

面试题

Java 基础

  1. Java 中 IO 流分为几种?
  2. BIO、NIO、AIO 有什么区别?
  3. Files的常用方法都有哪些?

多线程

  1. 并行和并发有什么区别?
  2. 线程和进程的区别?
  3. 守护线程是什么?
  4. 创建线程有哪几种方式?
  5. 说一下 runnable 和 callable 有什么区别?
  6. 线程有哪些状态?
  7. sleep() 和 wait() 有什么区别?
  8. notify()和 notifyAll()有什么区别?
  9. 创建线程池有哪几种方式?
  10. 线程的 run()和 start()有什么区别?
  11. 线程池都有哪些状态?
  12. 线程池中 submit()和 execute()方法有什么区别?
  13. 在 Java 程序中怎么保证多线程的运行安全?
  14. 多线程锁的升级原理是什么?
  15. 什么是死锁?
  16. 怎么防止死锁?
  17. ThreadLocal 是什么?有哪些使用场景?
  18. 说一下 synchronized 底层实现原理?
  19. synchronized 和 volatile 的区别是什么?
  20. synchronized 和 Lock 有什么区别?
  21. synchronized 和 ReentrantLock 区别是什么?
  22. 说一下 atomic 的原理?

spring/spring MVC

  1. 为什么要使用 spring?
  2. 解释一下什么是 aop?
  3. 解释一下什么是 ioc?
  4. spring 有哪些主要模块?
  5. spring 常用的注入方式有哪些?
  6. spring 中的 bean 是线程安全的吗?
  7. spring 支持几种 bean 的作用域?
  8. spring 自动装配 bean 有哪些方式?
  9. spring 事务实现方式有哪些?
  10. 说一下 spring 的事务隔离?
  11. 说一下 spring mvc 运行流程?
  12. spring mvc 有哪些组件?
  13. @RequestMapping 的作用是什么?
  14. @Autowired 的作用是什么?
    四、spring/spring Cloud
  15. 什么是 spring boot?
  16. 为什么要用 spring boot?
  17. spring boot 核心配置文件是什么?
  18. spring boot 配置文件有哪几种类型?它们有什么区别?
  19. spring boot 有哪些方式可以实现热部署?
  20. jpa 和 hibernate 有什么区别?
  21. 什么是 spring cloud?
  22. spring cloud 断路器的作用是什么?
  23. spring cloud 的核心组件有哪些?
    五、Mybatis
  24. mybatis 中 #{}和 ${}的区别是什么?
  25. mybatis 有几种分页方式?
  26. RowBounds 是一次性查询全部结果吗?为什么?
  27. mybatis 逻辑分页和物理分页的区别是什么?
  28. mybatis 是否支持延迟加载?延迟加载的原理是什么?
  29. 说一下 mybatis 的一级缓存和二级缓存?
  30. mybatis 和 hibernate 的区别有哪些?
  31. mybatis 有哪些执行器(Executor)?
  32. mybatis 分页插件的实现原理是什么?
  33. mybatis 如何编写一个自定义插件?
    六、kafk、Zookeeper
  34. kafka 可以脱离 zookeeper 单独使用吗?为什么?
  35. kafka 有几种数据保留的策略?
  36. kafka 同时设置了 7 天和 10G 清除数据,到第五天的时候消息达到了 10G,这个时候 kafka 将如何处理?
  37. 什么情况会导致 kafka 运行变慢?
  38. 使用 kafka 集群需要注意什么?
  39. zookeeper 是什么?
  40. zookeeper 都有哪些功能?
  41. zookeeper 有几种部署模式?
  42. zookeeper 怎么保证主从节点的状态同步?
  43. 集群中为什么要有主节点?
  44. 集群中有 3 台服务器,其中一个节点宕机,这个时候 zookeeper 还可以使用吗?
  45. 说一下 zookeeper 的通知机制?
    七、Redis
  46. Redis是什么?都有哪些使用场景?
  47. redis 有哪些功能?
  48. redis 和 memecache 有什么区别?
  49. redis 为什么是单线程的?
  50. redis在什么情况下会变慢?
  51. 什么是缓存穿透?怎么解决?
  52. redis 支持的数据类型有哪些?
  53. redis 支持的 Java 客户端都有哪些?
  54. Jedis 和 redisson 有哪些区别?
  55. 怎么保证缓存和数据库数据的一致性?
  56. redis 持久化有几种方式?
  57. redis 怎么实现分布式锁?
  58. redis 分布式锁有什么缺陷?
  59. redis 如何做内存优化?
  60. redis 淘汰策略有哪些?
  61. redis 常见的性能问题有哪些?该如何解决?
    八、 JVM
  62. 说一下 Jvm 的主要组成部分?及其作用?
  63. 说一下 Jvm 运行时数据区?
  64. 说一下堆栈的区别?
  65. 队列和栈是什么?有什么区别?
  66. 什么是双亲委派模型?
  67. 说一下类加载的执行过程?
  68. 怎么判断对象是否可以被回收?
  69. java 中都有哪些引用类型?
  70. 说一下 jvm 有哪些垃圾回收算法?
  71. 说一下 jvm 有哪些垃圾回收器?
  72. 详细介绍一下 CMS 垃圾回收器?
  73. 新生代垃圾回收器和老生代垃圾回收器都有哪些?有什么区别?
  74. 简述分代垃圾回收器是怎么工作的?
  75. 说一下 jvm 调优的工具?
  76. 常用的 jvm 调优的参数都有哪些?

Java线程执行native方法时程序计数器为空,如何确保native执行完后的程序执行的位置
native是非java代码编写的,比如C,C++, 它们无法在java编译时生成字节码,即JVM获取不到native实现,只能通过系统指令去调用native方法,所以执行native时程序计数器值为空undefined。native方法由原生平台直接执行,native方法执行后会退出(栈帧pop),方法退出返回到被调用的地方继续执行程序。

计算机

  • 为什么CPU的缓存还是那么小?

数据库

可以理解为socket和fd(file descriptor文件描述符)

10中网络ID
单线程同步 -> NTP
多线程同步 -> Natty
单线程异步 -> Redis
半同步半异步 -> Natty
多进程同步 -> fastcgi
多线程异步 -> memcached
多进程异步 -> nginx
每请求每进程(现场)-> Apache/CGI
微进程框架 -> erlang/go/lua
协议框架 -> libco/ntyco/libgo

单线程 epoll -> redis
多线程 epoll -> memcached
多进程 epoll -> nginx

epoll底层数据结构是红黑树,还有一个就绪队列。
while(1) {
    epoll_wait(epfd, events, 1024, -1)
}
epoll中的三个函数
epoll_create() 创建一个网络IO
epoll_ctl() 控制connection的
epoll_wait() 多长时间去轮询一次,看有没有数据
服务器端有个事件循环一直在监听有没有数据(缺点是一直占一个cpu)
  • 解释下同步/异步,阻塞/非阻塞
妈妈让我去厨房烧一锅水,准备下饺子
阻塞:水只要没烧开,我就干瞪眼看着这个锅,沧海桑田,日新月异,我自岿然不动,厨房就是我的家,烧水是我的宿命。
非阻塞:我先去我屋子里打把王者,但是每过一分钟,我都要去厨房瞅一眼,生怕时间长了,水烧干了就坏了,这样导致我游戏也心思打,果不然,又掉段了。
同步:不管是每分钟过来看一眼锅,还是寸步不离的一直看着锅,只要我不去看,我就不知道水烧好没有,浪费时间啊,一寸光阴一寸金,这锅必须发我13薪
异步:我在淘宝买了一个电水壶,只要水开了,它就发出响声,嗨呀,可以安心打王者喽,打完可以吃饺子喽~
总结:
阻塞/非阻塞:我在等你干活的时候我在干啥?
阻塞:啥也不干,死等
非阻塞:可以干别的,但也要时不时问问你的进度
同步/异步:你干完了,怎么让我知道呢?
同步:我只要不问,你就不告诉我
异步:你干完了,直接喊我过来就行

在讨论之前先说明一下IO发生时涉及到的对象和步骤,对于一个network IO,它会涉及到两个系统对象:
* application 调用这个IO的进程
* kernel 系统内核

那他们经历的两个交互过程是:
 阶段1 wait for data 等待数据准备
 阶段2 copy data from kernel to user 将数据从内核拷贝到用户进程中

秒杀系统

  1. 如何控制秒杀商品页面购买按钮的定时点亮?[抢买问题]
  2. 如何防止超卖?
  3. 如何防止重复下单?
  4. 排队下单,类似12306入Queue的操作
    参考答案:https://github.com/zhonghuasheng/JAVA/tree/master/seckill#

面试技巧

  1. 面试前出于礼貌和面试官确认自己讲话是否能被听懂,方言的问题
  2. 自我介绍尽量控制在35秒左右(基本信息介绍,工作经历介绍,求职的原因介绍)
  3. 在回答问题是使用我的理解是什么什么,不要去绝对回答这个问题,技术没有完全的对错,每个人对技术的理解都不同
  4. 面试过程中如果遇到自己没有接触到的知识点,可以这样说:这个知识点我们有接触过,我尝试回答一下我的理解

盘涅

  1. 集合你平时用的多的有哪些?
答:集合的话像Collection下的ArrayList, LinkedList; Set下的HashSet; Map下的HashMap,如果涉及到多线程,线程安全的话,会使用ConcurrentHashMap。
问:我们先聊一下ArrayList和LinkedList吧,它们两个在什么场景下会使用它?
答:ArrayList的底层数据结构是数组,不指定ArrayList大小的时候初始化的大小是0,第一次add的时候size会变成10,扩容的话会是之前的1.5倍。ArrayList由于底层是数组,因此随机查找的速度很快,插入和删除效率比较低。因为它底层是数组,因此分配内存空间的时候要求是连续的内存单元,所以如果需要存储的数据量很大的情况下,不建议使用ArrayList。LinkedList的底层是一个带有头节点和尾节点的双向链表,提供了头插(LinkedFirst)和尾插(LinkedLast),插入和删除比较快,不支持随机查询,LinkedList数据的存储不要求内存空间是连续的。
问:如果在多线程的情况下,我既想用List,又想保证线程安全,那怎么办?
答:我知道的有三种方式:1. 使用Vector,它是一个线程安全的List集合,所有的方法都加了synchronized关键字来保证同步,但它性能很差。[读写都加锁,底层也是数组,扩容时是之前的2倍] 2. 使用Collections.SynchronizedList,它是Collections下的一个静态内部类,它把List下的所有方法都变成了线程安全的,于Vector不同的是,它把synchronized加到了方法内部的代码块上,提高了扩展性[锁的粒度变小] 3. 使用CopyOnWriteArrayList,add的时候加锁,读的时候不加锁,提高了读取性能 [锁粒度变小,同时锁范围变小]
  1. 常规的来聊一下HashMap
答:HashMap在1.7的时候底层使用数组+单链表的数据结构,使用的是头插;1.8使用数组+单链表/红黑树,使用的是尾插。单链表和红黑树之间的转换,当单链表的长度大于等于8,并且它的hash桶大于等于64的时候,它会将单链表转换成红黑树形式存储;它在红黑树的节点的数量小于等于6的时候,它会重新再转换成一个单链表,这是它底层结构的一个变化;当我们往hashmap中put元素的时候,先根据key的hash值得到这个元素在数组中的位置(即下标),然后就可以把这个元素放到对应的位置中了。如果这个元素所在的位子上已经存放有其他元素了,那么在同一个位子上的元素将以链表的形式存放,新加入的放在链头,最先加入的放在链尾。从hashmap中get元素时,首先计算key的hashcode,找到数组中对应位置的某一元素,然后通过key的equals方法在对应位置的链表中找到需要的元素。从这里我们可以想象得到,如果每个位置上的链表只有一个元素,那么hashmap的get效率将是最高的;另外一点是关于它Hash桶的数量,默认是16个,默认的阀值是0.75,这关系到它的扩容。
问:它扩容是怎么扩容的?
答:扩容的时候首先检测数组中的元素个数,负载因子默认是loadFactor=0.75,因此当它哈希桶占用的容量大于12的时候,就会触发扩容,哈希桶会扩容成之前的两倍,把之前的元素再进行一次哈希运算,然后添加到新的哈希桶,然后按照链表或者红黑树重新排列起来。
问:你给我说下它是不是线程安全的?
答:它不是线程安全的,因为在插入操作的时候多线程会有数据覆盖的可能;另外它在1.7的时候,它在put的时候可能会有一个resize的过程,这个过程可能会照成它的头插会形成一个环形链表形成一个死循环,1.8之后改成尾插了。
问:你平时开发的时候怎么去保证它的线程安全?
答:我平时开发的时候会使用ConcurrentHashMap来保证它的线程安全。另外有HashTable也能保证线程安全,但是HashTable锁的是方法。`待续`
问:聊一聊ConcurrentHashMap
答:1.7的时候底层是一个分片数组,使用了segment锁(继承自ReentrantLock),通过每次只给一个段加锁来保证它的线程安全和并发度;另外,在1.8的时候,它改成了和HashMap一样的数据结构,使用数据加单链表或者红黑树的数据结构,在1.8的时候渐渐放弃了这种分片锁机制,而使用的是synchronized加CAS来做的,我们知道在1.6版本的时候JVM对synchronized的优化是非常大的,现在也是用这个方法来保证线程安全。
问:CAS是什么?
答:Compare And Sweep,比较并替换,是乐观锁的一种实现,在修改之前要将之前读到的值与当前内存中的值进行比较,如果一致就写入。CAS可以认为是一种轻量级的锁,在低并发的时候时候效率很快,在高并发的情况下,CAS需要涉及到CPU的计算,容易引起CPU性能的消耗,高并发的情况下还是建议使用状态机或者锁之类的。另外一点就是会产生ABA的问题,因为在读取和写入之间,可能有其他线程率先完成修改,然后又将值改回到之前,这样就误以为当前的值和读取的值是一致的,这个问题可以通过加一个戳或标志位来标识,也就是相当于加个版本号。
  1. 刚你提到了synchronized,再跟我聊下它
答:关于synchronized,可以用在同步代码块(可指定任意锁)/方法(指定this)/静态方法(指定class对象)。在1.6升级还是蛮大的,首先提供了无锁状态,然后是偏向锁,然后是轻量级锁,然后是重量级锁。偏向锁的话,见名知意,它偏向于获得第一个锁的线程,它会将id写到锁对象的对象头中,等其他线程来的时候,立即会升级到轻量级锁的状态(如果是同一个线程再次进入,先判断是否获取过锁,如果获取过标记位+1,否则修改为1),轻量级锁主要是在低并发的情况下来消除锁的方式,它主要是在你的虚拟机栈中开辟一个空间,叫做Lock Record,将锁对象的Mark Work写到Lock Record,再尝试Lock Record的指针使用CAS去修改锁对象头的那个区域来完成一个加锁的过程,如果再有线程进入的话,并尝试修改这个指针,轻量级锁会升级为一个自旋锁,如果10次未成功就会膨胀成一个重量级锁,也就是一个互斥锁的过程。重量级锁,使用synchronized的时候会在你的代码块前后加上两个指令,monitorenter和monitorexist,通过一个monitor监视器通过计数器的方式来监视这个锁的状态。如果是同步方法的时候,使用的是一个ACC_SYNCHRONIZED标志位,相当于flag,它自动走的是一个同步方法调用的策略,这个原理是比较简单的。
问:什么时候用它?什么时候用ReentrantLock,这个你有考虑吗?
答:有,它两对比的话区别还是蛮大的。从JVM层面来说,synchronized是JVM的一个关键字,ReetrantLock其实是一个类,你需要手动去编码,synchronized使用其实是比较简单的,不需要关心锁的释放;但是使用ReetrantLock的时候你需要手动去lock,然后配合tray finally然后去确保锁的释放,然后ReentrantLock相比synchronized有几个高级特性,当一个线程长期等待得不到锁的时候,你可以手动的去调用一个lockInterruptibly方法尝试中断掉不去等待;另外,它提供了一个公平锁的方式;此外,它提供了一个condition,你可以指定去唤醒绑定到condition身上的线程,来实现一个选择性通知的方式。如果不需要ReentrantLock需要的高级特性的话,建议还是使用synchronized的关键字。
例:因为锁不可逆,如果在早高峰的时候,滴滴打车上的所有锁都升级为重量级锁,那么等过了这个高峰,锁依然是重量级锁,会影响系统的QPS的,所以在使用的时候还是要更具具体的场景来使用
  1. volatile看过吗?
答:volatile修饰的变量保证了多线程下的可见性,当CPU写数据时,发现此变量被volatile修饰时,发现其他CPU中也存在该变量的副本,会发出信号通知其他CPU该变量的缓存行置为无效状态,因此当其他CPU需要读取这个变量时,发现自己缓存中的变量行是无效的,就重新去内存读取。它是通过计算机的总线嗅探机制(MESI)来实现的,当然它也会照成一个问题,就是volitale会一直嗅探,导致一些无效的交互,引发总线风暴。
赞(0) 打赏
未经允许不得转载:IDEA激活码 » java面试常见问题大全!准备春招面试必看!

一个分享Java & Python知识的社区