> 文档中心 > Java常见的一些面试题目

Java常见的一些面试题目

目录

一、数据库悲观锁使用的注意事项以及可能发生的问题?行级锁是什么?行级锁语句怎么写?语句里面where后的语句是什么?​介绍一下什么是悲观锁、乐观锁。

 二、Mysql事务隔离级别及实现原理?

三、说说数据库分库、分表、分区及其原则和目的?

四、数据库被锁的处理方法以及相关应对措施?​

五、​Mysql表设计原则,索引原理

六、​Mysql数据库优化方法?

七、左链接右链接和内链接的区别?

八、什么是索引,Mysql的最左索引匹配原则?

九、介绍一下java中常见的锁机制

十、HashMap 和 Hashtable 的区别

十一、说说线程池的工作原理?

十二、介绍一下java的异常体系?

十三、单例模式是线程安全的吗?如何实现线程安全?

十四、说一下常见的java的设计模式

十五、说说说排查jvm故障的思路?

十六、内存溢出的原因和解决办法?

十七、mybatis的-些常见坑和缓存机制是什么?

十八、说说mybatis的原理​

十九、介绍一下Spring原理

二十、spring和spring boot的区别

二十一、Spring事务的传播行为和隔离级别?

二十二、springboot starter的原理,soringboot的核心注解是什么?它主要由哪几个注解组成的?

二十三、介绍一下redis的概念与原理

二十四、redis中主从、哨兵和集群这三个有什么区别

二十五、dubbo的原理?

二十七、介绍一下zookeeper的概念、原理

二十八、说说对分布式事务的理解?分布式事务在实际开发中的使用情况?

二十九、说一下java常用的编码规范



一、数据库悲观锁使用的注意事项以及可能发生的问题?
行级锁是什么?行级锁语句怎么写?语句里面where后的语句是什么?​
介绍一下什么是悲观锁、乐观锁。

答: ​mysql锁分为共享锁和排他锁,也叫做读锁和写锁。
读锁是共享的,可以通过lock in share mode实现,这时候只能读不能写。
写锁是排他的,它会阻塞其他的写锁和读锁。从颗粒度来区分,可以分为表锁和行锁两种。
表锁会锁定整张表并且阻塞其他用户对该表的所有读写操作,比如alter修改表结构的时候会锁表。
行锁又可以分为乐观锁和悲观锁,悲观锁可以通过for update实现,乐观锁则通过版本号实现

 二、Mysql事务隔离级别及实现原理?

答:隔离性有4个隔离级别,分别是:
read uncommit 读未提交,可能会读到其他事务未提交的数据,也叫做脏读。
read commit 读已提交,两次读取结果不一致,叫做不可重复读。
不可重复读解决了脏读的问题,他只会读取已经提交的事务。​
repeatable read 可重复复读,这是mysql的默认级别,就是每次读取结果都一样,但是有可能产生幻读。
serializable 串行,一般是不会使用的,他会给每一行读取的数据加锁,会导致大量超时和锁竞争的问题。​
隔离性由MVCC来保证
MVCC叫做多版本并发控制,实际上就是保存了数据在某个时间节点的快照。
我们每行数实际上隐藏了两列,创建时间版本号,过期(删除)时间版本号,每开始一个新的事务,版本号都会自动递增。
MVCC的原理是查找创建版本小于或等于当前事务版本,删除版本为空或者大于当前事务版本。

三、说说数据库分库、分表、分区及其原则和目的?

答:​首先分库分表分为垂直和水平两个方式,一般来说我们拆分的顺序是先垂直后水平。
垂直分库
基于现在微服务拆分来说,都是已经做到了垂直分库了​
垂直分表
如果表字段比较多,将不常用的、数据较大的等等做拆分
水平分表
首先根据业务场景来决定使用什么字段作为分表字段​ 

四、数据库被锁的处理方法以及相关应对措施?​

答: 让事务超时失败
死锁的关键在于:两个(或以上)的Session加锁的顺序不一致。
那么对应的解决死锁问题的关键就是:让不同的session加锁有次序​ 

五、​Mysql表设计原则,索引原理

答:第一范式:1NF是对属性的原子性约束,要求属性具有原子性,不可再分解;
第二范式:2NF是对记录的惟一性约束,要求记录有惟一标识,即实体的惟一性;
第三范式:3NF是对字段冗余性的约束,即任何字段不能由其他字段派生出来,它要求字段没有冗余。
范式化设计优缺点:
优点:
可以尽量得减少数据冗余,使得更新快,体积小
缺点:对于查询需要多个表进行关联,减少写得效率增加读得效率,更难进行索引优化
反范式化:
优点:可以减少表得关联,可以更好得进行索引优化
缺点:数据冗余以及数据异常,数据得修改需要更多的成本。
索引按照数据结构来说主要包含B+树和Hash索引。​
B+树是左小右大的顺序存储结构,节点只包含id索引列,而叶子节点包含索引列和数据,这种数据和索引在一起存储的索引方式叫做聚簇索引,一张表只能有一个聚簇索引。假设没有定义主键,InnoDB会选择一个唯一的非空索引代替,如果没有的话则会隐式定义一个主键作为聚簇索引。
​非聚簇索引(二级索引)保存的是主键id值,这一点和myisam保存的是数据地址是不同的。 

六、​Mysql数据库优化方法?

答:1.SQL语句及索引的优化
2. 数据库表结构的优化
3.系统配置的优化
4.硬件的优化​  

七、左链接右链接和内链接的区别?

答:先说什么是交叉连接: 交叉连接又叫笛卡尔积,它是指不使用任何条件,直接将一个表的所有记录和另一个表中的所有记录一一匹配。
内连接 则是只有条件的交叉连接,根据某个条件筛选出符合条件的记录,不符合条件的记录不会出现在结果集中,即内连接只连接匹配的行。
外连接 其结果集中不仅包含符合连接条件的行,而且还会包括左表、右表或两个表中
的所有数据行,这三种情况依次称之为左外连接,右外连接,和全外连接。
左外连接,也称左连接,左表为主表,左表中的所有记录都会出现在结果集中,对于那些在右表中并没有匹配的记录,仍然要显示,右边对应的那些字段值以NULL来填充。右外连接,也称右连接,右表为主表,右表中的所有记录都会出现在结果集中。左连接和右连接可以互换,MySQL目前还不支持全外连接。 

八、什么是索引,Mysql的最左索引匹配原则?

答:索引就好比字典的目录一样 我们通常都会先去目录查找关键偏旁或者字母再去查找 要比直接翻查字典查询要快很多。
-- 假设有一张表,有id,name,age,gender四个字段,id是主键,name,age是组合索引列
-- 组合索引使用的时候必须先匹配name,然后匹配age
select * from table where name = ? and age = ? ;-- 生效
select * from table where name = ?;-- 生效
select * from table where age = ? ;-- 不生效
select * from table where age = ? and name = ? ;-- 生效
--在mysql内部有优化器会调整对应的顺序

九、介绍一下java中常见的锁机制

线程控制中常用的两个关键字的区别:synchronized、volatile
volatile 关键字怎么保证线程安全
答:synchronized是java提供的原子性内置锁,这种内置的并且使用者看不到的锁也被称为监视器锁,使用synchronized之后,会在编译之后在同步的代码块前后加上monitorenter和monitorexit字节码指令,他依赖操作系统底层互斥锁实现。他的作用主要就是实现原子性操作和解决共享变量的内存可见性问题。
相比synchronized的加锁方式来解决共享变量的内存可见性问题,volatile就是更轻量的选择,他没有上下文切换的额外开销成本。使用volatile声明的变量,可以确保值被更新的时候对其他线程立刻可见。volatile使用内存屏障来保证不会发生指令重排,解决了内存可见性的问题。

十、HashMap 和 Hashtable 的区别

答:线程不安全与线程安全

十一、说说线程池的工作原理?

线程池有哪几种,参数分别是什么?每个参数的作用是?
答:首先线程池有几个核心的参数概念:
最大线程数maximumPoolSize
核心线程数corePoolSize
活跃时间keepAliveTime
阻塞队列workQueue
拒绝策略RejectedExecutionHandler
当提交一个新任务到线程池时,具体的执行流程如下:
当我们提交任务,线程池会根据corePoolSize大小创建若干任务数量线程执行任务
当任务的数量超过corePoolSize数量,后续的任务将会进入阻塞队列阻塞排队
当阻塞队列也满了之后,那么将会继续创建(maximumPoolSize-corePoolSize)个数量的线程来执行任务,如果任务处理完成,maximumPoolSize-corePoolSize额外创建的线程等待keepAliveTime之后被自动销毁
如果达到maximumPoolSize,阻塞队列还是满的状态,那么将根据不同的拒绝策略对应处理

十二、介绍一下java的异常体系?

error和exception的区别?
答:异常的定义
异常就是有异于常态,和正常情况不一样,有错误出现。在java中,阻止当前方法或作用域的情况,称之为异常。
异常的分类
Error:是程序中无法处理的错误,表示运行应用程序中出现了严重的错误。此类错误一般表示代码运行时JVM出现问题。通常有Virtual MachineError(虚拟机运行错误)、NoClassDefFoundError(类定义错误)等。比如说当jvm耗完可用内存时,将出现OutOfMemoryError。此类错误发生时,JVM将终止线程。非代码性错误。因此,当此类错误发生时,应用不应该去处理此类错误。
Exception::程序本身可以捕获并且可以处理的异常。
运行时异常(不受检异常):RuntimeException类极其子类表示JVM在运行期间可能出现的错误。编译器不会检查此类异常,并且不要求处理异常,比如用空值对象的引用(NullPointerException)、数组下标越界(ArrayIndexOutBoundException)。此类异常属于不可查异常,一般是由程序逻辑错误引起的,在程序中可以选择捕获处理,也可以不处理。
非运行时异常(受检异常):Exception中除RuntimeException极其子类之外的异常。编译器会检查此类异常,如果程序中出现此类异常,比如说IOException,必须对该异常进行处理,要么使用try-catch捕获,要么使用throws语句抛出,否则编译不通过。​

十三、单例模式是线程安全的吗?如何实现线程安全?

答:懒汉模式不安全,DCL双重检查锁机制

十四、说一下常见的java的设计模式

答:单例模式:Spring 中的 Bean 默认情况下都是单例的。无需多说。
工厂模式:工厂模式主要是通过 BeanFactory 和 ApplicationContext 来生产 Bean 对象。
代理模式:最常见的 AOP 的实现方式就是通过代理来实现,Spring主要是使用 JDK 动态代理和 CGLIB 代理。
模板方法模式:主要是一些对数据库操作的类用到,比如 JdbcTemplate、JpaTemplate,因为查询数据库的建立连接、执行查询、关闭连接几个过程,非常适用于模板方法。

十五、说说说排查jvm故障的思路?

答:故障一、频繁FullGC的排查方法:
发生FGC有可能是内存分配不合理,比如Eden区太小,导致对象频繁进入老年代,这时候通过启动参数配置就能看出来,另外有可能就是存在内存泄露,可以通过以下的步骤进行排查:
1、jstat -gcutil或者查看gc.log日志,查看内存回收情况​
2、dump出内存文件在具体分析,比如通过jmap命令jmap -dump:format=b,file=dumpfile pid,导出之后再通过Eclipse Memory Analyzer等工具进行分析,定位到代码,修复​
故障二、CPU飙高,同时FGC的排查方法:
1、找到当前进程的pid,top -p pid -H 查看资源占用,找到线程
2、printf “%x\n” pid,把线程pid转为16进制,比如0x32d
3、jstack pid|grep -A 10 0x32d查看线程的堆栈日志,还找不到问题继续
4、dump出内存文件用MAT等工具进行分析,定位到代码,修复

十六、内存溢出的原因和解决办法?

一直执行正常的定时任务突然不执行了,可能是哪些原因导致的?如何判断以及解决?
答:情况一、堆内存溢出
​    一般的排查方式可以通过设置-XX: +HeapDumpOnOutOfMemoryError在发生异常时dump出当前的内存转储快照来分析,分析可以使用Eclipse Memory Analyzer(MAT)来分析
情况二、方法区(运行时常量池)和元空间溢出​
​    String对象
情况三、直接内存溢出
    常见的比如在NIO中可以使用native函数直接分配堆外内存就容易导致OOM的问题。​
情况四、​栈内存溢出
    如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常
    如果虚拟机栈可以动态扩展,并且扩展时无法申请到足够的内存,抛出OutOfMemoryError异常

十七、mybatis的-些常见坑和缓存机制是什么?

答:坑一、嵌套结果如果是collection的话,分页总数会存在问题
坑二、延迟加载失效
坑三、批量插入语句会因数据库不同而不同
一级缓存也叫本地缓存,MyBatis 的一级缓存是在会话(SqlSession)层面进行缓存的。MyBatis 的一级缓存是默认开启的,不需要任何的配置。
二级缓存是用来解决一级缓存不能跨会话共享的问题的,范围是namespace 级别的,可以被多个SqlSession 共享(只要是同一个接口里面的相同方法,都可以共享),生命周期和应用同步。

十八、说说mybatis的原理​

答:1、 mybatis配置SqlMapConfig.xml,此文件作为mybatis的全局配置文件,配置了mybatis的运行环境等信息。
mapper.xml文件即sql映射文件,文件中配置了操作数据库的sql语句。此文件需要在SqlMapConfig.xml中加载。
2、 通过mybatis环境等配置信息构造SqlSessionFactory即会话工厂
3、 由会话工厂创建sqlSession即会话,操作数据库需要通过sqlSession进行。
4、 mybatis底层自定义了Executor执行器接口操作数据库,Executor接口有两个实现,一个是基本执行器、一个是缓存执行器。
5、 Mapped Statement也是mybatis一个底层封装对象,它包装了mybatis配置信息及sql映射信息等。mapper.xml文件中一个sql对应一个Mapped Statement对象,sql的id即是Mapped statement的id。
6、 Mapped Statement对sql执行输入参数进行定义,包括HashMap、基本类型、pojo,Executor通过 Mapped Statement在执行sql前将输入的java对象映射至sql中,输入参数映射就是jdbc编程中对preparedStatement设置参数。
7、 Mapped Statement对sql执行输出结果进行定义,包括HashMap、基本类型、pojo,Executor通过 Mapped Statement在执行sql后将输出结果映射至java对象中,输出结果映射过程相当于jdbc编程中对结果的解析处理过程。

十九、介绍一下Spring原理

答:Spring是一个一个基于JAVA的框架,解决业务逻辑层于其他层级之间解耦的集合框架,集成各种框架所需的组件功能,核心是IOC,context,beans,DI等。

IOC 叫做控制反转,指的是通过Spring来管理对象的创建、配置和生命周期,这样相当于把控制权交给了Spring,不需要人工来管理对象之间复杂的依赖关系,这样做的好处就是解耦。在Spring里面,主要提供了 BeanFactory 和 ApplicationContext 两种 IOC 容器,通过他们来实现对 Bean 的管理。
AOP 叫做面向切面编程,他是一个编程范式,目的就是提高代码的模块性。Srping AOP 基于动态代理的方式实现,如果是实现了接口的话就会使用 JDK 动态代理,反之则使用 CGLIB 代理,Spring中 AOP 的应用主要体现在 事务、日志、异常处理等方面,通过在代码的前后做一些增强处理,可以实现对业务逻辑的隔离,提高代码的模块化能力,同时也是解耦。Spring主要提供了 Aspect 切面、JoinPoint 连接点、PointCut 切入点、Advice 增强等实现方式。

DI:是依赖注入,依赖IOC容器,在所需要的使用资源,对象,常量等时候注入到应用程序。

二十、spring和spring boot的区别

答:​约定优于配置和自动装配

简化配置,xml配置可以选择注解的方式注入bean

spring mvc Bean加载到IOC容器的过程:xml->Beandefine->BeanFactory

二十一、Spring事务的传播行为和隔离级别?

答:事务传播机制:
1、PROPAGATION_REQUIRED:如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务,这也是通常我们的默认选择。
2、PROPAGATION_REQUIRES_NEW:创建新事务,无论当前存不存在事务,都创建新事务。
3、PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则按REQUIRED属性执行。
4、PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
5、PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
6、PROPAGATION_MANDATORY:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就抛出异常。
7、PROPAGATION_SUPPORTS:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,就以非事务执行。

二十二、springboot starter的原理,soringboot的核心注解是什么?它主要由哪几个注解组成的?

答:原理:组件的META-INF文件下均含有spring.factories文件,自动配置模块中,SpringFactoriesLoader收集到文件中的类全名并返回一个类全名的数组,返回的类全名通过反射被实例化,就形成了具体的工厂实例,工厂实例来生成组件具体需要的bean。
核心注解:@SpringBootApplication
组成注解:@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan

二十三、介绍一下redis的概念与原理

答:基本数据类型:
1、字符串对象string:int整数、embstr编码的简单动态字符串、raw简单动态字符串
2、列表对象list:ziplist、linkedlist
3、哈希对象hash:ziplist、hashtable
4、集合对象set:intset、hashtable
5、有序集合对象zset:ziplist、skiplist
Redis为什么快:
1、完全基于内存操作
2、C语言实现,优化过的数据结构,基于几种基础的数据结构,redis做了大量的优化,性能极高
3、使用单线程,无上下文的切换成本
4、基于非阻塞的IO多路复用机制

二十四、redis中主从、哨兵和集群这三个有什么区别

答:主从模式是最简单的实现高可用的方案,核心就是主从同步。
哨兵(sentinel)的功能比单纯的主从架构全面的多了,它具备自动故障转移、集群监控、消息通知等功能
如果说依靠哨兵可以实现redis的高可用,如果还想在支持高并发同时容纳海量的数据,那就需要redis集群。redis集群是redis提供的分布式数据存储方案,集群通过数据分片sharding来进行数据的共享,同时提供复制和故障转移的功能。

二十五、dubbo的原理?

答:1、服务启动的时候,provider和consumer根据配置信息,连接到注册中心register,分别向注册中心注册和订阅服务
    2、register根据服务订阅关系,返回provider信息到consumer,同时consumer会把provider信息缓存到本地。如果信息有变更,consumer会收到来自register的推送
    3、consumer生成代理对象,同时根据负载均衡策略,选择一台provider,同时定时向monitor记录接口的调用次数和时间信息
    4、拿到代理对象之后,consumer通过代理对象发起接口调用
    5、provider收到请求后对数据进行反序列化,然后通过代理调用具体的接口实现

二十七、介绍一下zookeeper的概念、原理

答:概念:Zookeeper是一个开源的分布式协调服务,由雅虎公司创建,由于最初雅虎公司的内部研究小组的项目大多以动物的名字命名,所以后来就以Zookeeper(动物管理员)来命名了,而就是由Zookeeper来负责这些分布式组件环境的协调工作。
他的目标是可以提供高性能、高可用和顺序访问控制的能力,同时也是为了解决分布式环境下数据一致性的问题。
原理:
​Zookeeper通过ZAB原子广播协议来实现数据的最终顺序一致性,他是一个类似2PC两阶段提交的过程。
CAP是一个分布式系统设计的定理​

注:2PC协议在commit阶段发出commit或rollback通知后就不管了,若此时由于网络或系统原因,A执行commit/rollback成功,B执行失败,还是会出现数据不一致。此场景就需要考虑3PC、另一个独立Agent进程、超时机制等来确保事务无论如何都会被执行。

2PC文章:2PC两阶段提交协议 - 余正忠 - 博客园 (cnblogs.com)

3PC文章:关于2PC(二阶段提交)和3PC(三阶段提交)的理解_xj15010735572的博客-CSDN博客_二阶段提交

zookeeper文章:Zookeeper 3、Zookeeper工作原理(详细) - Bodi - 博客园 (cnblogs.com)

解决一致性的文章:一致性算法Paxos详解 - AiFly - 博客园 (cnblogs.com)

二十八、说说对分布式事务的理解?分布式事务在实际开发中的使用情况?

答:基于消息列来最终一致性的方案
    Seata框架

二十九、说一下java常用的编码规范

答:阿里巴巴编码规范​
1. hashCode和equals 的处理遵循以下规则:
    1)只要覆写equals ,就必须要覆写hashCode
    2)因为Set存储的是不重复的对象,依据hashCode和equals进行判断,所以Set存储的对象必须覆写这两个方法。
    3)如果自定义对象作为Map的键,那么必须覆写hashCode和equals。
2. 不要在foreach循环里进行元素的remove/add操作。remove元素请使用Iterator方式,如果并发操作,需要对Iterator对象加锁
3. 线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险
4. 必须回收自定义的ThreadLocal变量,尤其在线程池场景下,线程经常会被复用,如果不清理自定义的 ThreadLocal变量,可能会影响后续业务逻辑和造成内存泄露等问题。尽量在代理中使用try-finally块进行回收

 

素彩网