大家好,我是程序员牛肉。
临近暑假,不知道大家都找到实习没有。今天在某APP里闲逛,发现有人竟然七月份还能拿到美团的日常实习。我们来逐一解析一下他的面试题。
其实总体来看也不太难,但是涉及到八股并不多,因此靠死记硬背是走不通的。这里面的很多知识还是需要自己对Java有自己的理解。
那么在这里我们就看看这些面试题要如何回答:
01、Java的线程池是怎么设计的
Java的线程池设计是通过java.util.concurrent包中的ExecutorService接口实现的,它提供了一种灵活的线程池管理机制。线程池的主要设计目标是减少线程创建和销毁的开销,提高资源利用率和程序性能。以下是线程池设计的一些关键点:
- 线程复用:线程池维护一组线程,当任务提交给线程池时,线程池会尝试将任务分配给已有的空闲线程,而不是每次都创建新线程。
- 控制并发:线程池可以设定核心线程数和最大线程数,控制同时运行的线程数量,防止因线程过多导致系统资源耗尽。
- 任务队列:线程池通常包含一个任务队列,当所有线程都忙碌时,新提交的任务会被放入队列中等待执行。
- 线程生命周期管理:线程池可以自动管理线程的生命周期,包括线程的创建、执行任务、空闲等待以及销毁。
- 异常处理:线程池可以处理任务执行过程中的异常,保证线程池的稳定运行。
- 任务拒绝策略:当任务队列已满且线程池中的线程数达到最大值时,线程池需要定义一种策略来处理新提交的任务,比如丢弃任务、抛出异常或者运行一个额外的线程来处理任务。
02、核心线程数设置为多少合适
1.IO密集型任务
一般来说:文件读写、DB读写、网络请求等
推荐:核心线程数大小设置为2N 1 (N为计算机的CPU核数)
2.CPU密集型任务
一般来说:计算型代码、Bitmap转换、Gson转换等
推荐:核心线程数大小设置为N 1 (N为计算机的CPU核数)
03、Java中锁的分类和特点
1. 按锁的实现分类:
- 内置锁(Synchronized):
- 特点:由Java语言内置支持,通过synchronized关键字实现。
- 使用范围:方法或代码块。
- 作用:确保同一时刻只有一个线程可以执行特定代码段。
- 缺点:可能导致性能问题,因为它是一种重量级锁。
- 显式锁(Lock):
- 特点:需要通过java.util.concurrent.locks.Lock接口实现,如ReentrantLock。
- 使用范围:代码块。
- 作用:提供了比synchronized更灵活的锁定机制。
- 优点:支持尝试非阻塞获取锁、可中断的锁获取、超时等特性。
2. 按锁的作用范围分类:
- 方法锁:
- 特点:锁定整个方法。
- 适用场景:当整个方法需要同步执行时。
- 代码块锁:
- 特点:锁定一段特定的代码块。
- 适用场景:当只有部分代码需要同步执行时。
3. 按锁的可重入性分类:
- 可重入锁:
- 特点:同一个线程可以多次获取同一个锁。
- 例子:synchronized和ReentrantLock。
- 不可重入锁:
- 特点:一个线程不能多次获取同一个锁。
- 注意:Java标准库中没有提供不可重入锁的实现,但可以通过设计实现。
4. 按锁的公平性分类:
- 公平锁:
- 特点:按照线程请求锁的顺序来获取锁。
- 例子:ReentrantFairLock。
- 非公平锁:
- 特点:线程获取锁的顺序不一定按照请求的顺序。
- 例子:ReentrantLock默认是非公平锁。
5. 按锁的可中断性分类:
- 可中断锁:
- 特点:线程在尝试获取锁的过程中可以被中断。
- 例子:ReentrantLock。
- 不可中断锁:
- 特点:线程在尝试获取锁的过程中不能被中断。
- 例子:synchronized。
04、介绍一下java的反射机制
Java的反射机制是一种在运行时检查或修改程序行为的能力。它允许程序在运行时动态地加载类、查询类信息、创建对象、调用方法、访问字段等。反射是Java语言的一个重要特性,它提供了以下主要功能:
- 类加载:通过反射,可以在运行时加载一个类,而不需要在编译时就知道这个类。
- 类型检查:可以检查一个对象是否属于某个特定的类或接口。
- 创建对象:可以使用反射机制动态地创建类的实例,即使这个类的构造函数是私有的。
- 访问字段:可以访问类的私有字段,甚至可以修改其值。
- 调用方法:可以调用类的方法,包括私有方法。
- 获取类信息:可以获取类的各种信息,如类名、方法列表、字段列表等。
- 修改访问控制:可以修改访问控制,访问或修改私有成员。
05、MySQL事务的原子性如何保证
1.事务日志(transaction log):MySQL使用事务日志记录对数据库的所有修改操作。在事务执行期间,所有的修改操作都会被写入事务日志,而不是直接写入磁盘上的数据文件。这意味着即使在事务执行过程中发生故障,MySQL可以通过回滚日志来撤销事务中的操作,使数据回滚到事务开始前的状态,从而保证原子性。
2.回滚日志(undo log):MySQL使用回滚日志记录对事务进行回滚操作所需的信息。当事务需要回滚时,MySQL可以使用回滚日志中的信息来还原修改操作,将数据恢复到事务开始之前的状态。回滚日志的存在可以确保在事务回滚时的原子性,即将所有操作全部回滚,不会留下部分修改。
3.锁机制:MySQL使用锁来控制对数据的并发访问,保证事务的隔离性和原子性。在事务执行期间,MySQL会根据事务的隔离级别对涉及的数据进行加锁,防止其他事务对数据进行修改。当事务成功提交或回滚后,MySQL会释放相应的锁,确保事务的原子性。
06、MySQL如何解决慢查询
1.查询语句应该尽量避免全表扫描,首先应该考虑在Where子句以及OrderBy子句上建立索引,但是每一条SQL语句最多只会走一条索引,而建立过多的索引会带来插入和更新时的开销,同时对于区分度不大的字段,应该尽量避免建立索引,可以在查询语句前使用explain关键字,查看SQL语句的执行计划,判断该查询语句是否使用了索引;
2.应尽量使用EXIST和NOT EXIST代替 IN和NOT IN,因为后者很有可能导致全表扫描放弃使用索引;
3.应尽量避免在Where子句中对字段进行NULL判断,因为NULL判断会导致全表扫描;
4.应尽量避免在Where子句中使用or作为连接条件,因为同样会导致全表扫描;
5.应尽量避免在Where子句中使用!=或者<>操作符,同样会导致全表扫描;
6.使用like “�c%” 或者like “�c” 同样也会导致全表扫描,而like “abc%”会使用索引。
7.在使用Union操作符时,应该考虑是否可以使用Union ALL来代替,因为Union操作符在进行结果合并时,会对产生的结果进行排序运算,删除重复记录,对于没有该需求的应用应使用Union ALL,后者仅仅只是将结果合并返回,能大幅度提高性能;
8.应尽量避免在Where子句中使用表达式操作符,因为会导致全表扫描;
9.应尽量避免在Where子句中对字段使用函数,因为同样会导致全表扫描
10.Select语句中尽量 避免使用“*”,因为在SQL语句在解析的过程中,会将“”转换成所有列的列名,而这个工作是通过查询数据字典完成的,有一定的开销;
11.Where子句中,表连接条件应该写在其他条件之前,因为Where子句的解析是从后向前的,所以尽量把能够过滤到多数记录的限制条件放在Where子句的末尾;
12.若数据库表上存在诸如index(a,b,c)之类的联合索引,则Where子句中条件字段的出现顺序应该与索引字段的出现顺序一致,否则将无法使用该联合索引;
13.From子句中表的出现顺序同样会对SQL语句的执行性能造成影响,From子句在解析时是从后向前的,即写在末尾的表将被优先处理,应该选择记录较少的表作为基表放在后面,同时如果出现3个及3个以上的表连接查询时,应该将交叉表作为基表;
07、请求到Spring Boot处理函数的流程
- 接收请求:
- 客户端(如浏览器或移动应用)向Spring Boot服务器发送HTTP请求。
- Tomcat作为内嵌容器:
- Spring Boot默认使用Tomcat作为内嵌容器来接收和处理HTTP请求。
- DispatcherServlet:
- 请求首先到达DispatcherServlet,它是Spring MVC的前端控制器,负责将请求路由到相应的处理器。
- HandlerMapping:
- DispatcherServlet使用HandlerMapping来确定请求应该由哪个处理器(Controller)来处理。
- HandlerInterceptor:
- 在请求到达Controller之前,可以被一系列的HandlerInterceptor拦截,用于执行前置处理。
- Controller:
- 请求被路由到相应的Controller中的处理函数(通常用@RequestMapping或其他注解标记)。
- 业务逻辑处理:
- Controller调用业务逻辑层(Service层)来处理请求。
- 数据访问:
- 如果需要,Service层会调用数据访问层(Repository或DAO层)来访问数据库或外部数据源。
- 返回结果:
- 业务逻辑处理完成后,Controller将处理结果返回给DispatcherServlet。
- 视图解析:
- 如果Controller返回的是视图名称,DispatcherServlet将使用视图解析器(ViewResolver)来解析视图。
- 渲染视图:
- 视图被渲染后,返回给客户端,如果是HTML页面,客户端浏览器将展示给用户。
- 返回响应:
- 如果是RESTful API,Controller可能直接返回JSON或XML响应。
- HandlerInterceptor的后置处理:
- 请求处理完成后,HandlerInterceptor可以执行一些后置处理。
- 请求完成:
- DispatcherServlet完成请求处理,并将响应发送回客户端。
- 日志记录:
- 整个请求处理过程可能会被日志记录,以便于问题排查和性能监控。
大致就是这些问题了,其实综合来看并不是很难。但是比较考察面试者真正的功力,大部分面试题已经不是八股的范围了,需要面试者在日常生活中就经常积累。