讯飞提前批一面
飞凡计划-研发方向
一面 技术面
1. 关于项目代码的提问。
因为我在简历上写了在腾讯实习8个月代码量3w行,故有以下提问。其实代码量大与业务复杂性有关,代码量多≠项目非常复杂,亦≠代码质量会很差。
a. 一个Java class比较合理的行数是多少,一个方法呢
一个Java类比较合理的行数为200行,如果超过500行最好考虑拆分类。方法大概在50行左右吧,超过100行就要考虑方法的拆分了。(理论上都是无限行数,但是因为IDE内存堆大小的限制,以及加载变量名,构建索引的效率,最好不要太长)
b. 在代码量这么大的项目中,如何保障代码质量,如何保证分支的测试覆盖率
使用设计模式给比较复杂的业务设计简单的处理逻辑,建造者,组合。使用自动化测试工具保证分支覆盖率等待
2. 数据库相关
a. 数据库三范式是什么
数据库的三范式是一组用于指导数据库设计的规范化原则,旨在减少数据冗余和提高数据完整性。这些范式是逐步增强的,每个范式都建立在前一个范式的基础上。以下是三个范式的简要说明:
第一范式(1NF) - 原子性
要求数据库表的每一列都是不可分割的原子数据项,即表中的所有字段都应该只包含单一值,而不能是集合、数组或对象等复杂数据结构。确保每个字段的值都是唯一的,避免数据重复。
第二范式(2NF) - 完全性
在满足第一范式的基础上,要求表中的每一列都应完全依赖于主键。也就是说,如果一个表有复合主键(由多个字段组成),那么非主键字段不能只依赖于复合主键的一部分。目的是解决部分依赖问题,即非主键字段只能依赖于主键字段,而不能只依赖于主键的一部分。
第三范式(3NF) - 非传递性
在满足第二范式的基础上,要求非主键字段不能相互依赖,即不能通过非主键字段来间接确定其他非主键字段的值。目的是消除传递依赖,确保数据表中只包含与主键直接相关的数据,避免数据冗余。
b. 数据库设计中,我们是遵守越多的范式好,还是越少的范式好
一般达到第三范式或者BC范式即可,越多的范式设计就越复杂,查询语句会涉及到很多连表查询,维护起来也很麻烦, 效率较低。
c. 有了解过分库分表吗
实际只用过根据用户ID和时间戳分
d. 索引优化
e. 索引失效
f. 如何使用缓存,加快数据库模糊查询
场景题,要求很多,不会
3. Java语言相关
a. Java如何实现异步,使用什么注解
应该是异步(async-await),对应SpringBoot的@Async注解
b. Java线程池有使用过吗,常见的参数有哪些
用过但是很久以前用的了。Java线程池是通过java.util.concurrent包中的ExecutorService接口实现的,它是Java并发编程中非常重要的一部分。线程池可以有效地管理线程的创建和销毁,降低资源消耗,提高系统性能。以下是创建和使用线程池的一些常见参数和概念:
核心线程数(Core Pool Size): 线程池中始终保持的线程数量,即使它们是空闲的。最大线程数(Maximum Pool Size): 线程池中允许的最大线程数量。如果所有线程都在忙,而任务队列已经满了,那么新任务将等待,直到一个线程变得可用。工作队列(Work Queue): 一个任务队列,用于存储等待执行的任务。这个队列可以是有界的,也可以是无界的。线程存活时间(Keep-Alive Time): 当线程池中正在运行的线程数量超过核心线程数时,多余的空闲线程能等待新任务的最长时间。超过这个时间后,多余的线程将被终止。拒绝策略(Rejected Execution Handler): 当任务太多来不及处理时,线程池会采取一种拒绝策略来拒绝新任务。常见的拒绝策略有: AbortPolicy:抛出一个RejectedExecutionException。CallerRunsPolicy:由调用者线程来运行任务。DiscardPolicy:默默地丢弃任务。DiscardOldestPolicy:丢弃队列里最老的任务,并将新任务加入队列。线程工厂(Thread Factory): 用于创建新线程的工厂。可以通过自定义线程工厂来设置线程名称或其他线程属性。调度器(Scheduler): 用于控制任务执行的时间和顺序。在定时任务或周期性任务中使用。以下是使用ThreadPoolExecutor创建线程池的一个例子:java
int corePoolSize = 5; // 核心线程数 int maximumPoolSize = 10; // 最大线程数 long keepAliveTime = 1L; // 线程存活时间,单位为秒 TimeUnit unit = TimeUnit.MINUTES; // 存活时间单位 BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(); // 工作队列 ThreadFactory threadFactory = Executors.defaultThreadFactory(); // 线程工厂 RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy(); // 拒绝策略 ThreadPoolExecutor executor = new ThreadPoolExecutor( corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler );
使用`Executors`类可以更方便地创建线程池,它提供了一些静态工厂方法来创建具有默认参数的线程池:
- `Executors.newCachedThreadPool()`:创建一个可根据需要创建新线程的线程池,但是会重用多余的空闲线程。
- `Executors.newFixedThreadPool(n)`:创建一个具有固定线程数的线程池。
- `Executors.newSingleThreadExecutor()`:创建一个只有一个线程的线程池。
- `Executors.newScheduledThreadPool(n)`:创建一个具有固定线程数的线程池,并且支持定时及周期性任务执行。
c. 后面看我Java太菜,干脆问些八股了
4. 有了解过服务熔断和服务降级的概念吗?
分布式
分布式系统就是将一个完整的系统按照业务功能拆分成很多独立的子系统,每个子系统就被称为“服务”,分布式系统将请求分拣和分发到不同的子系统,让不同的服务来处理不同的请求。在分布式系统中,子系统独立运行,它们之间通过网络通信连接起来实现数据互通和组合服务。
微服务
微服务架构是一种架构模式,它提倡将单一应用程序划分成一组小的服务,服务之间相互协调、互相配合,为用户提供最终价值。每个服务运行在其独立的进程中,服务和服务之间采用轻量级的通信机制相互沟通(通常是基于HTTP的Restful API).每个服务都围绕着具体的业务进行构建,并且能够被独立的部署到生产环境、类生产环境等。
DDD领域设计
不懂,看
DDD - 一文读懂DDD领域驱动设计-阿里云开发者社区 (aliyun.com)
5. 有了解过服务熔断和服务降级的概念吗?(直接背)
服务熔断
服务熔断的作用类似于我们家用的保险丝,当某服务出现不可用或响应超时的情况时,为了防止整个系统出现雪崩,暂时停止对该服务的调用。
服务降级
服务降级是当服务器压力剧增的情况下,根据当前业务情况及流量对一些服务和页面有策略的降级,以此释放服务器资源以保证核心任务的正常运行。降级往往会指定不同的级别,面临不同的异常等级执行不同的处理。 根据服务方式:可以拒接服务,可以延迟服务,也有时候可以随机服务。 根据服务范围:可以砍掉某个功能,也可以砍掉某些模块。 总之服务降级需要根据不同的业务需求采用不同的降级策略。主要的目的就是服务虽然有损但是总比没有好。
- 熔断VS降级~ 相同点目标一致:都是从可用性和可靠性出发,为了防止系统崩溃;用户体验类似:最终都让用户体验到的是某些功能暂时不可用;~ 不同点:触发原因不同:服务熔断一般是某个服务(下游服务)故障引起,而服务降级一般是从整体负荷考虑;