2/28 浩鲸云一面
自我介绍:
项目方面:在做过的项目和实习项目中挑一个来讲一下,这里讲的是实习项目的后端系统和当时比较印象深刻的问题和解决方法。然后有被问到这套系统之间相互通信的协议。
八股方面:
Q:有没有用过线程或者对线程池有没有了解?讲一下个人理解。
A:在多线程和高并发场景中,需要大量创建线程来处理业务,创建线程通常有三种方式,继承Thread类,实现Runnable和实现Callable接口,创建这三种线程使用结束后都会被虚拟机销毁,数量多的情况下,创建和销毁会消耗大量的系统资源,这时候可以使用线程池,可以将使用完成的线程回收利用,系统大量使用线程时,线程池可以减少创建线程数量,节省系统资源。
Q:怎么理解线程安全?
A:在多线程环境中,所有线程安全共享数据,不会导致出错或数据不一致的情况。因为多个线程可能会同时读取和修改同一份数据,如果没有适当的管理,可能会导致数据不一致,出现竞争条件。死锁等问题。同步和使用锁可以确保线程安全。
Q:创建线程的方式有几种?
A:继承Thread类,实现Runnable和实现Callable接口,线程池回收利用。
Q:创建线程是为了异步操作,那么如何让两个线程按顺序执行?这里回答的是加锁。
A: 1.我们可以利用Thread中的join方法解决线程顺序问题
2.使用 CountDownLatch
3.使用 CyclicBarrier
4.使用 ExecutorService 和 invokeAll
Q:你提到了加锁,那么加锁的关键字是什么?
A:synchornized关键字
Q:你怎么理解乐观锁和悲观锁?
A:乐观锁就是持乐观态度,认为在操作数据时别的线程不会同时来修改数据,所以不会上锁,但是在更新的时候会判断在此期间别的线程有没有更新过该数据。适合读多的场景。
悲观锁就是每次访问数据的时候都会上锁,这样别的线程想拿到这个数据就会阻塞直到它拿到锁。适合写多的场景。
好比在家里上厕所,觉得没人会在自己上厕所的时候进厕所,那么就不会锁门;但是在公共卫生间就会怕别人在自己上厕所同时来开门上厕所,所以就必须要锁门,这就是乐观锁和悲观锁的区别。
Q:Synchornized关键字是悲观锁还是乐观锁?
A:悲观锁
关于异常
Q:哪些异常属于运行时异常?忘记了
A:运行时异常:空指针异常、数组下标越界、指定类不存在、数学运算异常、不兼容异常、没有权限、实例化错误、堆栈溢出等
编译时异常:sql异常、IO异常、文件找不到、输入过程意外到达文件或流的末尾。
Q:那空指针和sql异常属于什么异常?
A:分别是运行时异常和编译时异常
Q:说一下序列化和反序列化? 那泛型呢? JAVA的反射机制呢?
A:序列化和反序列化:把Java对象转换为字节序列的过程和将字节序列恢复成Java对象的过程。
泛型:泛型也就是“参数化类型”,本质是为了将类型参数化,数据类型被设置为一个参数,在使用时再从外部传入一个数据类型,传入数据类型如果不匹配,编译器会直接报错;主要作为是为了简化相同模板类型的重复编写,提供更强大的类型检查。
反射:程序运行状态下,对于任何一个类,都能够知道这个类的所有属性和方法;对于任何一个类对象,都能够条用它的任何属性和方法;这种动态获取信息以及动态调用对象方法的功能就是Java语言的反射机制。
工作原理是:当一个字节码文件加载到内存的时候,JVM会对该字节码进行解剖,然后创建一个对象的Class对象,JVM把字节码文件的信息全部都存储到该Class对象中,我们只要获取到Class对象,我们就可以使用该对象设置对象的属性或者调用对象的方法等操作。
Q:看到简历写了熟悉Springboot,那么对spring底层熟悉吗,比如ioc和aop?
A: IOC:控制反转,简单来说就是把复杂的系统分解成相互合作的对象,这些对象类通过封装后,内部实现对外部透明,降低问题复杂度;该机制将全部对象的控制权上交给IOC容器,由容器创建和管理对象的依赖问题,使之成为系统的关键核心,把系统的所有对象粘合在一起发挥作用。
AOP:面向切面编程,像日志记录、事务管理、性能监测等类似和核心业务没直接关系,但又贯穿多个模块的功能被叫做横切关注点,这类功能通常分散在多个类中,导致代码重复,难以维护,而AOP允许我们将这些关注点集中到一个地方(切面),就相当于包装到一起,并自动织入到相关的业务逻辑中,使得代码更加简洁,可维护。切面使用 @Aspect 注解来标记,并作为 Spring 管理的 Bean。
Q:平常有没有使用到ioc和aop做一些东西?
A:待补充
Q:对jvm有了解吗?比如内存溢出?
A: JVM,Java虚拟机,组成部分有方法区、堆内存、虚拟机栈、本地方法栈和程序计数器。
内存溢出:Java程序在运行过程中,申请的内存超过了JVM所能提供的最大内存限制,导致程序无法执行抛出异常。
堆内存溢出:堆内存中存储的对象过多,或无用对象没有被垃圾回收器回收。
方法区溢出:加载过多的类(如动态生成类或大量使用反射)或元空间内存配置过小。
虚拟机栈溢出:虚拟机栈用于存储方法调用的栈帧,如果方法调用深度过大,会导致栈空间耗尽。需优化算法或检查代码中的递归调用,确保有正确的退出条件。
本地方法栈溢出:用于执行本地方法,若本地方法调用过深,可能导致溢出;需检查本地方法的调用情况。
Q:数据库里面用过MySQL和Oracle吗?数据库的事务和锁这里有概念吗?
A: 事务是由一组sql语句组成的逻辑单元,这组操作要么全部执行成功,要么全部执行失败。
事务的特性:原子性、一致性、隔离性和持久性。
事务的生命周期:开始(启动事务)、执行(执行sql操作)、提交(事务完成后提交修改)和回滚(事务失败,回滚到事务开始前的状态)。
锁是数据库用来控制并发访问的机制,用于确保多个事务访问同一数据时不会互相干扰。
共享锁:用于读操作,允许多个事务同时获取共享锁;其他事务可加共享锁,不能加排他锁。
排他锁:用于写操作,一个事务在写数据时加排他锁;其他事务不能加锁。
意向锁:表示事务有意向对表中的某些行加锁。
Q:如果一条sql执行很慢,有考虑过怎么优化吗?可以建立索引 索引这东西是越多越好吗? 结构比数量更重要。
A:优化索引(添加缺失的索引、避免过度索引、使用复合索引)、使用缓存、重写SQL查询。
无效索引过多也会导致系统臃肿,降低查询效率。
Q:有时候是建了索引还是很慢,说明没走索引,有哪几种情况不走索引? like模糊查询 百分号放前面和放后面是不一定能读到索引。
A: 在查询条件中使用了函数或表达式,导致无法使用索引。
索引未在最左侧
NULL值问题也可能导致不使用索引。
Q:表连接有几种方式? 左关联有几种写法?
A:内连接(查询两表中都存在的相关数据)、左连接(左表所有数据无论右表是否匹配)、右连接(右表所有数据无论左表是否匹配)、全外连接(两个表所有数据,不论是否匹配)、交叉连接(笛卡尔积)、自连接(同一表中的关联数据)
Linux
Q:查看文件有几种方式?
A:cat、less、more、head、tail、vim/vi
Q:看JAVA进程在不在用哪个命令? 看正在运行的进程有哪些呢?
A:可以使用ps结合grep命令查看Java进程是否存在;
ps aux | grep java
ps aux:显示所有用户的进程信息。
grep java:过滤出包含 “java” 关键字的行
Q:有用过ps -ef吗?
A: ps -ef (Process Status缩写)是一个常用的命令,用于显示当前系统中所有进程的详细信息。
ps: 查看进程状态的命令。
-e: 显示所有进程(包括其他用户的进程)。
-f: 以完整的格式显示进程信息。
Q:中间件这块有用过什么?比如消息队列和缓存?
A: 消息队列:用于在分布式系统中解耦生产者和消费者之间的通信。生产者将消息发送到消息队列,消费者从队列中接收并处理消息。常见的包括RibbitMQ、Kafka、RocketMQ、ActiveMQ等。
作用:异步处理:生产者发送消息后无需等待消费者处理,提高系统响应速度。
解耦:生产者和消费者无需直接通信,降低模块之间的依赖性。
流量削峰:在高峰期将请求放入队列,消费者按处理能力消费消息,避免系统过载。
可靠性:消息队列通常支持持久化,系统崩溃消息也不会丢失。
顺序性:某些队列保证消息的顺序性。
缓存:缓存是一种临时存储技术,用于存储高频访问的数据,以减少对数据库或其他慢速存储的访问,从而提高系统性能。常见的缓存包括Redis、Cache等。
作用:加速数据访问:将热点数据存储在内存中,减少对数据库的查询。
降低后端负载:减少对数据库或外部API的访问频率,保护后端资源。
高并发支持:缓存可以快速响应大量请求,适合高并发场景。