2023-09-27 06:30:25
三七互娱Java一面主要围绕Java基础、多线程、数据库、框架及项目优化等方面展开,具体涉及以下内容:
Java内存模型相关
Java的内存模型,堆栈方法区等的区别:Java内存模型(JMM)规定了线程如何和何时可以看到由其他线程修改过后的共享变量的值,以及在必要时如何同步的访问共享变量。堆是线程共享的,用于存储对象实例和数组,是垃圾回收的主要区域;栈是线程私有的,每个线程都有独立的栈空间,用于存储局部变量表、操作数栈、动态链接、方法出口等信息;方法区也是线程共享的,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
每个线程虚拟机栈是共有的还是私有的:每个线程的虚拟机栈是私有的,线程创建时就会分配一个独立的虚拟机栈,线程结束时栈销毁。
多线程相关
多线程需要共享一个变量的做法:可以使用volatile关键字修饰变量,保证变量的可见性;也可以使用同步机制,如synchronized关键字、Lock接口实现类等,确保同一时间只有一个线程访问共享变量;还可以使用线程安全的数据结构,如ConcurrentHashMap、CopyOnWriteArrayList等。
多线程操作同一变量可能出现的问题:可能出现线程安全问题,如数据不一致、脏读等。例如,多个线程同时对一个变量进行自增操作,由于操作不是原子性的,可能导致最终结果小于预期值。
解决多线程操作同一变量问题的方法:除了上述提到的volatile、同步机制、线程安全数据结构外,还可以使用CAS(Compare-And-Swap,比较并交换)操作,它是一种无锁算法,通过比较内存中的值和预期值,如果相同则进行更新,否则重试,直到成功为止。
CAS属于什么锁,怎么定义乐观锁:CAS不属于传统意义上的锁,它是一种无锁算法。乐观锁是一种并发控制机制,它认为多线程并发修改数据时,产生冲突的概率比较小,所以先不加锁,在更新数据时判断是否有其他线程修改了数据,如果有则进行相应的处理(如重试),CAS就是乐观锁的一种实现方式。
数据库上实现乐观锁:可以在数据库表中添加一个版本号字段,每次更新数据时,将版本号加1。在更新数据前,先读取版本号,更新时判断当前版本号是否和读取的版本号一致,如果一致则更新,否则说明数据已被其他线程修改,不进行更新或进行重试。
线程池相关
线程池参数设置及实践:线程池的主要参数包括核心线程数、最大线程数、空闲线程存活时间、工作队列、线程工厂、拒绝策略等。核心线程数是指线程池中始终保持的线程数量,即使线程空闲也不会被销毁;最大线程数是指线程池中允许的最大线程数量;空闲线程存活时间是指当线程数量超过核心线程数时,空闲线程等待新任务的最长时间;工作队列用于存储等待执行的任务;线程工厂用于创建新线程;拒绝策略用于处理当线程池和队列都已满时,新任务的处理方式。在实际应用中,需要根据任务的类型(CPU密集型、IO密集型)、系统的负载情况等因素合理设置这些参数。
CPU密集和IO密集任务:CPU密集型任务是指需要大量CPU计算的任务,如复杂的算法计算、视频编码等,这类任务应尽量减少线程切换,核心线程数可以设置为接近或等于CPU核心数。IO密集型任务是指需要进行大量IO操作的任务,如文件读写、网络请求等,由于IO操作会阻塞线程,所以可以设置较多的线程数,以提高系统的吞吐量。
数据库索引相关
MySQL索引有哪些,根据什么原则加索引:MySQL常见的索引类型有普通索引、唯一索引、主键索引、联合索引、全文索引等。加索引的原则包括:为经常用于查询条件的列加索引;为经常用于排序和分组的列加索引;为经常用于连接的列加索引;避免为选择性低的列加索引,如性别列;索引列的数据类型尽量小;联合索引遵循最左前缀原则。
加索引提速的原因及底层结构:加索引可以提速是因为索引是一种数据结构,它可以快速定位到数据所在的位置,减少磁盘IO操作。MySQL中常用的索引结构是B+树,B+树是一种多路平衡查找树,它的所有数据都存储在叶子节点上,且叶子节点之间通过指针连接,形成一个有序链表,这样可以提高范围查询的效率。
随意加索引的负面影响:会增加数据库的存储空间;会降低写入性能,因为每次写入数据时都需要更新索引;可能会导致索引失效,如使用了函数、隐式转换等操作,使索引无法被使用。
B+树时间复杂度:B+树的查询时间复杂度为O(log n),其中n为树中元素的个数。
主键索引和普通索引区别,存储的区别:主键索引是一种特殊的唯一索引,它不允许有空值,一个表只能有一个主键索引。普通索引允许有空值,一个表可以有多个普通索引。在存储上,主键索引的叶子节点存储的是完整的数据记录,而普通索引的叶子节点存储的是主键值,需要通过主键值回表查询完整的数据记录。
SQL优化相关
排查慢SQL问题及解决:可以通过开启慢查询日志,记录执行时间超过阈值的SQL语句;使用EXPLAIN命令分析SQL语句的执行计划,查看是否使用了索引、扫描的行数等信息;根据分析结果进行优化,如优化查询条件、添加合适的索引、避免全表扫描等。
慢查询问题的监控办法:除了开启慢查询日志外,还可以使用性能监控工具,如Prometheus、Grafana等,实时监控数据库的性能指标,如查询响应时间、吞吐量等,及时发现慢查询问题。
缓存相关
缓存雪崩、击穿、穿透介绍及解决方法:缓存雪崩是指大量的缓存同时失效,导致大量的请求直接访问数据库,造成数据库压力过大。解决方法包括设置不同的过期时间、使用分布式缓存、提前缓存热点数据等。缓存击穿是指一个热点数据的缓存过期,此时大量的请求同时访问该数据,导致数据库压力过大。解决方法包括使用互斥锁、设置热点数据永不过期等。缓存穿透是指查询一个不存在的数据,由于缓存中没有该数据,所以每次请求都会直接访问数据库。解决方法包括使用布隆过滤器、缓存空值等。
布隆过滤器的判断方式及底层结构:布隆过滤器是一种空间效率高的概率型数据结构,用于判断一个元素是否在一个集合中。它由一个二进制数组和多个哈希函数组成,当向布隆过滤器中添加一个元素时,会使用多个哈希函数计算该元素的哈希值,并将对应的二进制数组位置设置为1。当判断一个元素是否在集合中时,会使用相同的哈希函数计算哈希值,并检查对应的二进制数组位置是否都为1,如果都为1则认为元素可能在集合中,否则一定不在集合中。
Redis相关
Redis做成分布式锁的原理:Redis可以通过SETNX(SET if Not eXists)命令实现分布式锁,该命令只有在键不存在时才会设置键值对,返回1表示获取锁成功,返回0表示获取锁失败。获取锁成功后,可以使用EXPIRE命令设置锁的过期时间,防止死锁。释放锁时,需要判断释放的是自己持有的锁,可以使用Lua脚本保证原子性。
多个Redis节点加锁:可以使用Redlock算法,该算法的基本思想是在多个独立的Redis节点上尝试获取锁,如果获取到大多数节点的锁,则认为获取锁成功,否则认为获取锁失败。
框架相关
Mybatisplus原理,实现在xml文件里写SQL及注入:Mybatisplus是对Mybatis的增强工具,它在Mybatis的基础上提供了更多的功能,如代码生成器、条件构造器、分页插件等。在xml文件中写SQL和Mybatis类似,Mybatisplus会在启动时解析xml文件,将SQL语句封装成MappedStatement对象,并注册到配置对象中。在注入方面,Mybatisplus通过Spring的依赖注入机制,将Mapper接口注入到Service层中。
动态代理的两种类型及AOP采用的类型:动态代理有两种类型,JDK动态代理和CGLIB动态代理。JDK动态代理是基于接口实现的,它要求目标类必须实现一个接口,通过反射机制创建代理对象。CGLIB动态代理是基于继承实现的,它通过继承目标类创建子类,并在子类中重写方法实现代理。AOP(面向切面编程)主要采用JDK动态代理和CGLIB动态代理,Spring AOP默认使用JDK动态代理,如果目标类没有实现接口,则使用CGLIB动态代理。
代理使用是否必须有接口及切面类定义:JDK动态代理必须有接口,CGLIB动态代理不需要接口。定义切面的类可以不用接口,切面类中可以定义通知方法,如@Before、@After、@Around等,用于在目标方法执行前后插入额外的逻辑。
其他
AI及Spring AI的应用:AI可以应用于智能客服、推荐系统、风险控制等领域。Spring AI是Spring框架对AI开发的支持,它提供了一些便捷的工具和接口,方便开发者集成AI模型,如TensorFlow、PyTorch等。
知识库二次优化及检索不准问题优化:对于知识库的二次优化,可以对知识进行分类整理,建立更合理的索引结构,提高检索效率。对于检索不准的问题,可以采用多种检索算法结合的方式,如基于关键词的检索和基于语义的检索相结合,提高检索的准确性。