admin管理员组文章数量:1794759
JAVA三年经验面试题总结
文章目录
- 面试题
- JAVA
- jvm、gc
- jdk1.8的新特性
- java基础
- 框架
- spring
- spring boot
- mybatis/mybatis-plus/springDataJpa
- mysql
- sql优化
- 索引
- 事务
- redis
- 应用场景
- 多线程
- 服务器相关
- 算法
- TCP/HTTP/WebSocket
- 业务
聊聊你对jvm的认识 JVM由JVM运行时数据区、执行引擎、本地库接口、本地方法库组成。 JVM运行时数据区,分为线程共享部分(方法区、堆)和线程隔离区(虚拟机栈、本地方法栈和程序计数器)。 1.1. 方法区 用于存储已被虚拟机加载的类信、常量、静态变量、即时编译器编译后的代码等数据。 运行时常量池(Runtime Constant Pool)是方法区的一部分。.Class文件中除了有类的版本/字段/方法/接口等描述信外,还有一项信是常量池(Constant Pool Table),用于存放编译期生成的各种字面量和符号引用,这部分内容将类在加载后进入方法区的运行时常量池中存放. 运行时常量区的内容并不只是在编译期间产生,通过String.intern()也可以实现在运行时向常量区中添加内容。 需要注意的是:从JDK8开始,方法区被元数据区替代了。具体的原因和两者的区别可以参考官网。 2.堆 是JVM中最大的一块内存区域,该区域的目的只是用于存储对象实例及数组。该区域也是GC的最主要区域。 根据Java虚拟机规范的规定,Java堆可以处于物理上不连续的内存空间中,只要逻辑上是连续的即可,就像我们的磁盘空间一样.在实现时,既可以实现固定大小的,也可以是可扩展的,不过当前主流的虚拟机都是按照可扩展来实现的(通过-Xmx和-Xms控制).如果在堆中没有内存完成实例分配,并且堆也无法再扩展时,就会抛出OutOfMemoryError异常。 3.虚拟机栈 每个线程方法在执行时都会创建一个栈帧,包含局部变量表、返回地址、操作数栈等信。每个方法的执行与完成就对应的栈帧的入栈与出栈过程 。局部变量表占用空间的大小在编译期就确定了。这里需要注意:如果线程请求的栈深度大于虚拟机所允许的深度,将会抛出StackOverflowError异常;如果虚拟机栈可以动态扩展(当前大部分的Java虚拟机都可动态扩展,只不过Java虚拟机规范中也允许固定长度的虚拟机栈),当扩展时无法申请到足够的内存时将会抛出OutOfMemoryError异常。 4.本地方法栈 与虚拟机栈类似,不过其中执行是本地方法。对于HotSpot虚拟机而言,本地方法栈和虚拟机栈是统一的。 5.程序计数器 是一个小的内存空间,如果线程正在执行的是一个java方法,则此内存区域记录正在执行的虚拟机字节码指令的地址;如果线程正在执行的是native方法,则计算器中的值为空。此内存区域是唯一一个在JAVA虚拟机规范中没有规定任何OutOfMemoryError情况的区域。
这几部分都有相关的JDK自带工具可以分析查看,比如jps, jstack, jmap, jhat, jstat等,还有图形化工具jconsole,jvisualvm,但对于Linux服务器就无能为力了。 好了,关于JVM就讲完了,接下来进行提问:JVM哪些区域会发生OOME,以及各自原因是什么? 堆内存不足是最常见的 OOM 原因之一,抛出的错误信是“java.lang.OutOfMemoryError:Java heap space”,原因可能千奇百怪,例如,可能存在内存泄漏问题;也很有可能就是堆的大小不合理,比如我们要处理比较可观的数据量,但是没有显式指定 JVM 堆大小或者指定数值偏小;或者出现 JVM 处理引用不及时,导致堆积起来,内存无法释放等。 而对于 Java 虚拟机栈和本地方法栈,这里要稍微复杂一点。如果我们写一段程序不断的进行递归调用,而且没有退出条件,就会导致不断地进行压栈。类似这种情况,JVM 实际会抛出 StackOverFlowError;当然,如果 JVM 试图去扩展栈空间的的时候失败,则会抛出 OutOfMemoryError。 对于老版本的 Oracle JDK,因为永久代的大小是有限的,并且 JVM 对永久代垃圾回收(如,常量池回收、卸载不再需要的类型)非常不积极,所以当我们不断添加新类型的时候,永久代出现 OutOfMemoryError 也非常多见,尤其是在运行时存在大量动态类型生成的场合;类似 Intern 字符串缓存占用太多空间,也会导致 OOM 问题。对应的异常信,会标记出来和永久代相关:“java.lang.OutOfMemoryError: PermGen space”。 随着元数据区的引入,方法区内存已经不再那么窘迫,所以相应的 OOM 有所改观,出现 OOM,异常信则变成了:“java.lang.OutOfMemoryError: Metaspace”。 直接内存不足,也会导致 OOM。
对GC了解哪些 参考链接:谈谈对Java GC的了解
事务的传播机制
PROPAGATION_REQUIRED | 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。 |
PROPAGATION_SUPPORTS | 支持当前事务,如果当前没有事务,就以非事务方式执行。 |
PROPAGATION_MANDATORY | 使用当前的事务,如果当前没有事务,就抛出异常。 |
PROPAGATION_REQUIRES_NEW | 新建事务,如果当前存在事务,把当前事务挂起。 |
PROPAGATION_NOT_SUPPORTED | 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。 |
PROPAGATION_NEVER | 以非事务方式执行,如果当前存在事务,则抛出异常。 |
PROPAGATION_NESTED | 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。 |
事务的四大特性
- 原子性:事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生一样。
- 一致性:事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。因此当数据库只包含成功事务提交的结果时,就说数据库处于一致性状态。
- 隔离性:同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。
- 持久性:指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其执行结果有任何影响。
事务的隔离级别(该问题存在于事务的并发问题,mysql默认的事务隔离级别为repeatable-read)
读未提交(read-uncommitted) | 是 | 是 | 是 |
不可重复读(read-committed) | 否 | 是 | 是 |
可重复读(repeatable-read) | 否 | 否 | 是 |
串行化(serializable) | 否 | 否 | 否 |
- 脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据
- 不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。
- 幻读:系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。
乐观锁与悲观锁,如何实现乐观锁 4.1 概念:
- 悲观锁:假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作
- 悲观锁,从字面理解就是很悲观,每次去拿数据的时候都认为别人会修改,所以在每次拿的时候对数据上锁,这样就保证了数据的准确性。比如mysql中的表锁,行锁。
- 乐观锁:假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。
- 乐观锁,在每次去拿数据的时候认为别人不会修改,不对数据上锁,但是在提交更新的时候会判断在此期间数据是否被更改,如果被更改则提交失败。
4.2 实现:
- 使用版本控制字段,再利用行锁的特性实现乐观锁,如下 有一张订单表order,有字段id、order_no、 price, 为实现乐观锁控制,添加version字段,默认值为0
id | 1 |
order_no | 123456 |
price | 5 |
version | 0 |
redis主要用来做什么 众多语言都支持Redis,因为Redis交换数据快,在服务器中常用来存储一些需要频繁调取的数据,节省内存开销,也极大的提升了速度。 将一些热点数据存储到Redis中,要用的时候,直接从内存取,极大的提高了速度和节约了服务器的开销。
- 会话缓存(最常用)
- 消队列(支付)
- 活动排行榜或计数
- 发布,订阅消(消通知)
- 商品列表,评论列表
在你项目中哪里用到了redis,用来做了什么(主要讲讲在自己项目中怎么用的就行,会往深了的业务问) 参考链接:redis常见应用场景
linux下载安装jdk需要哪些命令 参考链接:linux下安装jdk 详细步骤
docker的挂载,是否做过自动化部署 参考链接:docker基础知识之挂载本地目录 参考链接:Docker自动化部署(超详细)
nginx的应用场景
nginx的正向、反向代理
- 正向代理:服务器位于客户端和服务器之间,为了从服务器获取数据,客户端要向代理服务器发送一个请求,并指定目标服务器,代理服务器将目标服务器返回的数据转交给客户端。这里客户端需要要进行一些正向代理的设置的。 正向代理中被代理的是客户端的请求(比如翻墙)
- 反向代理:客户端对代理是无感知的,客户端不需要任何配置就可以访问,客户端将请求发送到反向代理服务器,由反向代理服务器去选择目标服务器获取数据后,在返回给客户端,此时反向代理服务器和目标服务器对外就是一个服务器,暴露的是代理服务器地址,隐藏了真实服务器IP地址。
- 产生粘包问题的两个原因: 1、发送方产生粘包:TCP协议通信连续多次调用send向对方发送数据,如果两次调用send的时间间隔极短,TCP协议为提高传输效率会将两次发送数据打包为一个数据包发送(Nagle算法) 2、接收方产生粘包:如果在接收方接收数据时,接收方没有及时调用recv接收数据而下一个数据包又发送过来则recv在接收数据时会将两个或多个数据当做一个数据包处理,同样会产生数据粘包现象
- 解决方法: 1、取消TCP协议的优化机制(不是很好,降低传输效率)调用Setsockopt函数 2、延长连续两次发送数据的时间间隔(比如调动Sleep函数) 3、加包头(在发送数据之前先发送数据的大小,类型等相关信)或者加间隔(在每段数据的结尾添加标识符以区分不同的数据段),一般包头数据都是定长的(项目中最完美的解决方案也是最常用的解决方案) 接收方粘包问题的解决方案:对于接收只能尽可能的及时接收数据以避免粘包
- controller层:
- service层:
文章部分内容参考链接: wwwblogs/jpcflyer/p/10666099.html blog.csdn/lp2388163/article/details/80683383 wwwblogs/cye9971-/p/11267431.html blog.csdn/you_ranxi/article/details/103048747 www.voidcn/article/p-srcudkft-gq.html 感谢各位原创作者,“我们不生产水,我们只是大自然的搬运工”。 总的来说三年经验面试官问的基础问题变少了,开始问框架底层实现,从事java开发还是要做深做广,该文仅记录本人面试经验,若有错误之处还请指出,谢谢。
版权声明:本文标题:JAVA三年经验面试题总结 内容由林淑君副主任自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.xiehuijuan.com/baike/1686828415a107669.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论