八股文总结2

发布于:2025-08-12 ⋅ 阅读:(18) ⋅ 点赞:(0)

目录

1. 谈谈你对Spring MVC的理解?​​

​​2. 简述MyBatis的插件运行原理,如何编写一个插件?​​

​​3. MyBatis是否支持延迟加载?实现原理?​​

​​4. MyBatis能执行一对一、一对多关联查询吗?实现方式及区别?​​

​​5. MyBatis如何将SQL结果封装为目标对象?映射形式?​​

​​6. MyBatis映射文件中,A标签通过include引用B标签,B能否定义在A后面?​​

​​7. MyBatis动态SQL怎么设定?语法?​​

​​8. MyBatis的Executor执行器有哪些?区别?​​

​​9. 为什么说MyBatis是半自动ORM?与全自动的区别?​​

​​10. 简单介绍MyBatis的理解?​​

​​11. 介绍一下Spring的事务管理?​​

​​12. SSM优缺点、使用场景?​​

​​13. Spring MVC的工作流程?​​

​​14. Spring MVC和Struts2的区别?​​

​​15. 如何把数据放入Session?​​

​​16. Spring MVC的执行流程?​​

​​17. MyBatis的好处是什么?​​

​​18. Bean工厂和ApplicationContext的区别?​​

​​19. Spring支持的Bean作用域?​​

​​20. 什么是Bean的自动装配?​​

​​21. 什么是基于Java的Spring注解配置?举例说明​​

​​22. 使用Spring通过什么方式访问Hibernate?​​

​​23. 如何通过HibernateDaoSupport整合Spring和Hibernate?​​

​​24. Spring框架事务管理的优点​​

​​25. AOP中连接点(JoinPoint)和切入点(Pointcut)的区别​​

​​26. AOP的作用及核心概念​​

​​27. @Autowired和@Resource的区别​​

​​28. TCP协议字段及可靠传输机制​​

​​29. 三次握手与四次挥手​​

​​30. 深拷贝与浅拷贝​​

​​31. 访问器如何保障线程安全?举例说明​​

​​32. 抽象类和接口的异同​​

​​33. final关键字能否防止指令重排序?能否代替volatile?​​

​​34. static修饰的模块什么时候初始化?​​

​​35. 对象锁与类锁的区别​​

​​36. 进程和线程的区别及通信方式​​

​​37. 类锁和对象锁是否互斥?​​

​​38. 注解的作用目标​​

​​39. 内部类的分类及场景​​

​​40. finally的作用及场景​​

​​41. 栈溢出 vs 堆溢出 vs 堆外内存​​

​​42. Java集合类框架​​

​​43. 泛型实现与示例​​

​​44. 反射获取私有信息的风险控制​​

​​45. 线程状态转换​​

​​46. thread.start()后的状态变化​​

​​47. 等待队列 vs 阻塞队列​​

​​48. sleep() vs wait()​​

​​49. sleep(1)的作用与场景​​

​​50. 中断机制与响应示例​​

​​51. 守护线程 vs 协程​​

​​52. 死锁条件与避免策略​​

​​53. 基本类型存储区域​​

​​54. 多线程使用场景​​

​​55. throw vs throws​​

​​56. Object类方法解析​​

​​57. 总线锁优缺点​​

​​58. 多线程顺序输出控制​​

​​59. 懒汉式单例模式​​

​​60. Tomcat访问Controller原理​​


1. 谈谈你对Spring MVC的理解?​

​答案:​
Spring MVC是基于Java的轻量级Web框架,采用MVC架构模式:

  • ​Model​​:数据模型(POJO/Map)
  • ​View​​:视图渲染(JSP/Thymeleaf)
  • ​Controller​​:处理请求(@Controller注解)

​核心组件:​

  1. ​DispatcherServlet​​:前端控制器,统一分发请求
  2. ​HandlerMapping​​:映射URL到Controller
  3. ​ViewResolver​​:解析逻辑视图名到物理视图

​特点:​

  • 松耦合(通过DI和IoC)
  • 支持RESTful风格
  • 集成验证、拦截器等


​2. 简述MyBatis的插件运行原理,如何编写一个插件?​

​答案:​
​运行原理:​
基于JDK动态代理,拦截四大核心组件:

  • Executor(执行SQL)
  • ParameterHandler(参数处理)
  • ResultSetHandler(结果集处理)
  • StatementHandler(SQL构建)

​编写步骤:​

  1. 实现Interceptor接口,重写intercept方法
  2. 使用@Intercepts注解声明拦截目标
  3. 在mybatis-config.xml中注册插件

​示例代码:​

@Intercepts({@Signature(type=Executor.class, method="update", args={MappedStatement.class, Object.class})})  

public class MyPlugin implements Interceptor {  

    @Override  

    public Object intercept(Invocation invocation) throws Throwable {  

        // 前置处理  

        Object result = invocation.proceed(); // 执行原方法  

        // 后置处理  

        return result;  

    }  

}  


​3. MyBatis是否支持延迟加载?实现原理?​

​答案:​
​支持延迟加载​​(懒加载),通过动态代理实现:

  1. ​配置​​:在mybatis-config.xml中启用:

<settings>  

    <setting name="lazyLoadingEnabled" value="true"/>  

</settings>  

​原理​​:

    • 查询主对象时,返回代理对象(如Proxy.newProxyInstance)
    • 当访问关联对象时,触发代理逻辑执行额外SQL(只有在代码实际访问关联属性时(如order.getDetails()),MyBatis才会通过动态代理触发二次SQL查询,实现按需加载。


​4. MyBatis能执行一对一、一对多关联查询吗?实现方式及区别?​

​答案:​
​支持两种方式:​

  1. ​嵌套查询(分步查询)​
    • 通过<association>(一对一)或<collection>(一对多)
    • 执行多条SQL,可能产生N+1问题
  2. ​嵌套结果(联合查询)​
    • 单条SQL联表查询,通过resultMap手动映射
    • 性能更高,但SQL复杂度增加

​区别:​

方式

性能

复杂度

适用场景

嵌套查询

较低

简单

关联数据较少时

嵌套结果

复杂

需要优化查询性能


​5. MyBatis如何将SQL结果封装为目标对象?映射形式?​

​答案:​
​封装过程:​

  1. 通过ResultSetHandler处理JDBC结果集
  2. 根据resultType或resultMap映射字段到对象属性

​映射形式:​

  1. ​自动映射​​:字段名与属性名一致(如user_name → userName)
  2. ​手动映射​​:<resultMap>显式配置字段与属性对应关系
  3. ​构造函数映射​​:通过<constructor>标签匹配构造参数


​6. MyBatis映射文件中,A标签通过include引用B标签,B能否定义在A后面?​

​答案:​
​可以​​。MyBatis解析XML时会将所有标签加载到内存,因此<sql id="B">可以定义在<include refid="B">之后,无顺序要求。


​7. MyBatis动态SQL怎么设定?语法?​

​答案:​
​动态SQL标签:​

  • <if>:条件判断
  • <choose>/<when>/<otherwise>:多分支选择
  • <foreach>:遍历集合(如IN查询)
  • <where>/<set>`:智能处理前缀后缀

​示例:​

<select id="findUser" parameterType="map" resultType="User">  

    SELECT * FROM user  

    <where>  

        <if test="name != null">AND name = #{name}</if>  

        <if test="age != null">AND age = #{age}</if>  

    </where>  

</select>  


​8. MyBatis的Executor执行器有哪些?区别?​

​答案:

​Executor 是 MyBatis 执行 SQL 的核心组件​​,负责 SQL 执行、缓存、事务和延迟加载。


​三种执行器:​

  1. ​SimpleExecutor​​:默认,每次执行新PreparedStatement
  2. ​ReuseExecutor​​:复用预处理语句(缓存Statement)
  3. ​BatchExecutor​​:批量执行更新操作

​区别:​

执行器

性能

适用场景

SimpleExecutor

一般

简单查询

ReuseExecutor

较高

高频重复SQL

BatchExecutor

最高

批量插入/更新


​9. 为什么说MyBatis是半自动ORM?与全自动的区别?​

​答案:​

​ORM(Object-Relational Mapping,对象关系映射)​​ 是一种编程技术,用于在 ​​面向对象编程语言​​(如 Java、Python)和 ​​关系型数据库​​(如 MySQL、PostgreSQL)之间建立映射关系,使开发者能够以操作对象的方式操作数据库,而无需直接编写 SQL。


​半自动ORM​​:

  • 需手动编写SQL和映射(灵活控制SQL优化)
  • 如MyBatis、JdbcTemplate

​全自动ORM​​:

  • 自动生成SQL(如Hibernate的HQL)
  • 牺牲灵活性换取开发效率

​核心区别:​

特性

半自动ORM

全自动ORM

SQL控制

开发者手动编写

框架自动生成

性能优化

更灵活

受限于框架实现


​10. 简单介绍MyBatis的理解?​

​答案:​
MyBatis是持久层框架,核心特点:

  1. ​SQL与代码分离​​:通过XML/注解配置SQL
  2. ​结果集映射​​:灵活的结果集到对象映射
  3. ​动态SQL​​:支持条件拼接
  4. ​插件扩展​​:可拦截核心组件逻辑

​与JDBC对比优势:​

  • 减少样板代码(如Connection管理)
  • 内置连接池、缓存机制


​11. 介绍一下Spring的事务管理?​

​答案:​

编程式事务侵入到了业务代码里面,但是提供了更加详细的事务管理;而声明式事务由于基于AOP,所以既能起到事务管理的作用,又可以不影响业务代码的具体实现。
Spring事务管理的核心是​​声明式事务​​(通过注解或XML配置)和​​编程式事务​​(通过代码控制)。

​关键特性:​

  1. ​事务传播行为​​(如REQUIRED、REQUIRES_NEW)
  2. ​隔离级别​​(如READ_COMMITTED、SERIALIZABLE)
  3. ​回滚规则​​(指定哪些异常触发回滚)

​实现方式:​

  • ​注解驱动​​:

@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT)  

public void transferMoney() { ... }  

  • ​XML配置​​:

<tx:advice id="txAdvice">  

    <tx:attributes>  

        <tx:method name="transfer*" propagation="REQUIRED"/>  

    </tx:attributes>  

</tx:advice>  

​底层依赖​​:

  • 使用AOP拦截@Transactional方法,通过PlatformTransactionManager(如DataSourceTransactionManager)管理事务。


​12. SSM优缺点、使用场景?​

​答案:​
​SSM框架组合​​:Spring(IoC/AOP) + Spring MVC(Web层) + MyBatis(持久层)。

框架

优点

缺点

使用场景

​Spring​

松耦合、易扩展

配置复杂(XML/注解混合)

需要依赖管理的企业级应用

​Spring MVC​

RESTful支持、灵活视图解析

学习曲线较陡

需要精细控制HTTP请求的应用

​MyBatis​

SQL可控、性能优化灵活

需手动编写SQL和映射

复杂SQL或需深度优化的项目

​典型场景​​:电商后台、金融系统等需要平衡灵活性与性能的项目。


​13. Spring MVC的工作流程?​

​答案:​
​核心流程​​(简化版):

  1. ​DispatcherServlet​​接收HTTP请求。
  2. ​HandlerMapping​​解析URL,找到对应@Controller。
  3. ​Controller​​处理请求,返回逻辑视图名或@ResponseBody数据。
  4. ​ViewResolver​​将逻辑视图名解析为物理视图(如JSP路径)。
  5. ​View​​渲染响应,返回客户端。

​关键扩展点​​:

  • 拦截器(HandlerInterceptor)
  • 异常处理器(@ExceptionHandler)


​14. Spring MVC和Struts2的区别?​

​答案:​

特性

Spring MVC

Struts2

​架构​

基于Servlet API

基于Filter链

​性能​

更高(无拦截器栈开销)

较低(OGNL表达式解析慢)

​配置​

注解驱动为主

XML配置为主

​线程安全​

Controller默认单例

Action每次请求创建实例

​趋势​​:Spring MVC已成为主流,Struts2因安全漏洞逐渐淘汰。


​15. 如何把数据放入Session?​

​答案:​
​Spring MVC中两种方式​​:

  1. ​直接操作HttpSession​​:

@Controller  

public class UserController {  

    @RequestMapping("/login")  

    public String login(HttpSession session) {  

        session.setAttribute("user", user);  

        return "home";  

    }  

}  

  1. ​使用@SessionAttributes注解​​(仅限Controller内共享):

@SessionAttributes("user")  

public class UserController { ... }  


​16. Spring MVC的执行流程?​

​答案:​
(与第13题部分重复,此处补充细节)

  1. ​请求到达​​:DispatcherServlet#doDispatch()处理。
  2. ​拦截器​​:执行preHandle()。
  3. ​参数绑定​​:HandlerAdapter处理@RequestParam等注解。
  4. ​返回值处理​​:
    • 若返回String,走视图解析流程;
    • 若返回@ResponseBody,由HttpMessageConverter序列化为JSON/XML。


​17. MyBatis的好处是什么?​

​答案:​

  1. ​SQL可控​​:避免全自动ORM的复杂查询性能问题。
  2. ​动态SQL​​:灵活拼接条件。
  3. ​轻量级​​:无侵入性,与Spring集成简单。
  4. ​缓存机制​​:一级缓存(Session级)、二级缓存(全局)。


​18. Bean工厂和ApplicationContext的区别?​

​答案:​

特性

BeanFactory(基础接口)

ApplicationContext(扩展接口)

​Bean加载时机​

懒加载(getBean时初始化)

预加载(启动时初始化所有Bean)

​国际化支持​

有(MessageSource

​事件机制​

支持ApplicationEvent发布订阅

​推荐​​:生产环境优先用ApplicationContext(如ClassPathXmlApplicationContext)。


​19. Spring支持的Bean作用域?​

​答案:​

  1. ​singleton​​(默认):单例,IoC容器中唯一实例。
  2. ​prototype​​:每次请求创建新实例。
  3. ​request​​:HTTP请求生命周期(Web环境)。
  4. ​session​​:HTTP会话生命周期(Web环境)。
  5. ​application​​:ServletContext生命周期(Web环境)。

​配置方式​​:

@Scope("prototype")  

@Component  

public class UserService { ... }  


​20. 什么是Bean的自动装配?​

​答案:​
​自动装配(Autowiring)​​:Spring自动注入依赖的Bean,无需显式配置。

​四种模式​​:

  1. ​byType​​:按类型匹配(需唯一Bean)。
  2. ​byName​​:按属性名匹配Bean ID。
  3. ​constructor​​:构造函数参数自动装配。
  4. ​no​​(默认):手动配置依赖。

​注解驱动​​:

@Service  

public class OrderService {  

    @Autowired  // byType优先  

    private UserService userService;  

}  

​限制​​:

  • 歧义性需配合@Qualifier解决。
  • 基本类型(如int)无法自动装配。


​21. 什么是基于Java的Spring注解配置?举例说明​

​答案:​
基于Java的配置是通过@Configuration类替代XML文件,核心注解包括:

  1. @Configuration​:标记类为配置源
  2. @Bean​:定义Bean实例(方法级别)
  3. @ComponentScan​:自动扫描组件
  4. @PropertySource​:加载配置文件

​示例:​

@Configuration

@ComponentScan("com.example")

@PropertySource("classpath:app.properties")

public class AppConfig {

    @Bean

    public DataSource dataSource() {

        return new DriverManagerDataSource(url, user, pwd);

    }

}


​22. 使用Spring通过什么方式访问Hibernate?​

​答案:​
​两种主要方式:​

  1. ​HibernateTemplate​​(已淘汰):

@Autowired

private HibernateTemplate hibernateTemplate;

public User getById(Long id) {

    return hibernateTemplate.get(User.class, id);

}

​原生Hibernate API​​(推荐):

    1. 通过LocalSessionFactoryBean配置SessionFactory
    2. 使用@Transactional管理事务


​23. 如何通过HibernateDaoSupport整合Spring和Hibernate?​

​答案:​
​步骤:​

  1. 继承HibernateDaoSupport类
  2. 注入SessionFactory
  3. 通过getHibernateTemplate()操作数据库

​示例:​

@Repository

public class UserDaoImpl extends HibernateDaoSupport implements UserDao {

    @Autowired

    public void setSessionFactoryDI(SessionFactory sf) {

        super.setSessionFactory(sf);

    }

    

    public List<User> findAll() {

        return getHibernateTemplate().loadAll(User.class);

    }

}


​24. Spring框架事务管理的优点​

​答案:​

优点

说明

​统一API​

支持多种持久层技术(JDBC/Hibernate/JPA)

​声明式事务​

通过注解解耦业务代码与事务逻辑

​传播行为控制​

支持7种事务传播级别

​集成测试​

与Spring Test模块无缝协作


​25. AOP中连接点(JoinPoint)和切入点(Pointcut)的区别​

​答案:​

概念

定义

示例

​连接点​

程序执行过程中的特定点(如方法调用、异常抛出)

UserService.login()方法执行

​切入点​

通过表达式匹配的连接点集合

@Pointcut("execution(* com.service.*.*(..))")


​26. AOP的作用及核心概念​

​答案:​
​三大作用:​

  1. 解耦横切关注点(日志/事务/安全)
  2. 动态增强对象功能
  3. 避免重复代码

​核心概念:​

  • ​切面(Aspect)​​:模块化横切逻辑的类(@Aspect),切入点+通知
  • ​通知(Advice)​​:增强的具体实现(前置/后置/环绕等)
  • ​织入(Weaving)​​:将切面应用到目标对象的过程


​27. @Autowired和@Resource的区别​

​答案:​

特性

@Autowired

@Resource

来源

Spring框架

JSR-250标准

注入方式

默认byType

默认byName

required属性

支持

不支持

名称指定

需配合@Qualifier

直接通过name属性


​28. TCP协议字段及可靠传输机制​

​答案:​
​关键字段:​

  • 序列号/确认号:保证数据有序到达
  • 标志位(SYN/ACK/FIN):控制连接状态
  • 窗口大小:流量控制

​可靠传输机制:​

  1. 三次握手建立连接
  2. 超时重传
  3. 滑动窗口控制流量
  4. 四次挥手释放连接

​滑动窗口作用:​

  • 解决网络拥塞
  • 提高信道利用率


​29. 三次握手与四次挥手​

​答案:​
​三次握手流程:​

  1. Client→Server:SYN=1, seq=x
  2. Server→Client:SYN=1, ACK=1, seq=y, ack=x+1
  3. Client→Server:ACK=1, seq=x+1, ack=y+1

​四次挥手流程:​

  1. Client→Server:FIN=1, seq=u
  2. Server→Client:ACK=1, ack=u+1
  3. Server→Client:FIN=1, seq=v
  4. Client→Server:ACK=1, ack=v+1


​30. 深拷贝与浅拷贝​

​答案:​

类型

特点

实现方式

​浅拷贝​

拷贝只复制对象的引用,而不复制对象本身。也就是说,新旧对象共享同一块内存。如果修改了新对象,原对象也会受到影响。浅复制适用于对象的属性是基本类型的情况,但如果属性是引用类型,则会导致两个对象共享同一个引用。

Object.clone()

​深拷贝​

拷贝会创建一个完全独立的新对象,新对象与原对象不共享内存。修改新对象不会影响原对象。深复制适用于对象的属性是引用类型的情况,因为它会递归地复制所有层级的对象属性和数组元素。

序列化/手动递归复制

​示例:​

// 深拷贝实现

public class DeepCopy implements Serializable {

    public Object copy() throws IOException, ClassNotFoundException {

        ByteArrayOutputStream bos = new ByteArrayOutputStream();

        ObjectOutputStream oos = new ObjectOutputStream(bos);

        oos.writeObject(this);

        

        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());

        ObjectInputStream ois = new ObjectInputStream(bis);

        return ois.readObject();

    }

}


​31. 访问器如何保障线程安全?举例说明​

​答案:​
​线程安全访问器的实现方式:​

  1. ​同步方法​​(synchronized):

public class Counter {

    private int count;

    public synchronized void increment() {

        count++;

    }

}

  1. ​锁机制​​(ReentrantLock):

private Lock lock = new ReentrantLock();

public void safeAccess() {

    lock.lock();

    try {

        // 临界区代码

    } finally {

        lock.unlock();

    }

}

  1. ​原子类​​(AtomicInteger等):

private AtomicInteger atomicCount = new AtomicInteger();

public void add() {

    atomicCount.incrementAndGet();

}

​典型场景​​:多线程环境下的计数器、共享资源配置。


​32. 抽象类和接口的异同​

​答案:​

在面向对象编程中,抽象类(Abstract Class)和接口(Interface)是两种不同的概念,它们都可以用来定义类的行为。抽象类是一种不能被实例化的类,它可以包含抽象方法和具体方法,而接口则是一种特殊的类,只包含抽象方法和常量。

抽象类的特点

抽象类使用 abstract 关键字定义。

抽象类中可以包含抽象方法和具体方法。

抽象类不能直接实例化,需要通过子类来实例化。

子类继承抽象类必须实现所有的抽象方法,除非子类也是抽象类。

抽象类的构造方法可以被定义,用于子类调用。

接口的特点

接口使用 interface 关键字定义。

接口只能包含抽象方法和常量(在Java 8之前)。

接口不能被实例化,也不能定义构造方法。

一个类可以实现多个接口。

接口中的方法默认是 public abstract,变量默认是 public static final

抽象类与接口的主要区别

实现方式:类可以实现多个接口,但只能继承一个抽象类。

方法定义:抽象类可以有具体方法的实现,而接口只能有抽象方法(Java 8之后,接口也可以有默认方法和静态方法)。

变量定义:抽象类中可以有各种类型的变量,接口中的变量默认是 public static final 类型。

构造方法:抽象类可以有构造方法,接口不能有构造方法。

访问修饰符:抽象类的访问修饰符可以是 public 或默认,接口中的方法和变量默认是 public

特性

抽象类

接口(Java 8+)

​实例化​

不能实例化

不能实例化

​方法实现​

可包含具体方法

默认方法(default)可实现

​构造方法​

​多继承​

单继承

多实现

​变量类型​

无限制

默认public static final

​相同点​​:都不能直接实例化,都可包含抽象方法。


​33. final关键字能否防止指令重排序?能否代替volatile?​

​答案:​

​final与指令重排序​​:
final能保证构造函数内的初始化操作不会被重排序到构造函数外(JMM保证)

​final vs volatile​​:

维度

final

volatile

可见性

仅保证构造完成后的可见性

保证实时可见性

原子性

不保证

保证单次读/写原子性

适用场景

不可变对象

多线程共享变量

​结论​​:不能互相替代。


​34. static修饰的模块什么时候初始化?​

​答案:​
​初始化时机:​

  1. ​静态变量/代码块​​:类加载时按顺序初始化
  2. ​静态内部类​​:首次访问时加载(延迟加载)
  3. ​静态方法​​:调用时加载方法区指令

​示例:​

class Example {

    static { System.out.println("静态块"); } // 类加载时执行

    static int x = initX(); // 立即初始化

    

    static class Inner { /* 延迟加载 */ }

}


​35. 对象锁与类锁的区别​

​答案:

对象锁是针对对象实例的同步锁。当一个方法被synchronized修饰时,它锁定的是调用该方法的对象实例。因此,如果一个类的两个不同实例对象被两个线程访问,每个线程都会持有各自实例的锁,这允许它们并发执行。然而,如果两个线程操作的是共享数据,那么可能无法保证线程安全,因为每个对象实例有自己的锁。

类锁则是针对类的class对象的同步锁。当一个静态方法被synchronized修饰时,它锁定的是类的class对象。这意味着,无论一个类有多少个实例对象,类锁始终只有一把,所有实例共享这把锁。因此,即使是不同对象的实例,它们在访问同步的静态方法时也会被阻塞,直到持有类锁的线程释放锁。

锁类型

作用范围

锁对象

示例

​对象锁​

单个实例

this/实例变量

synchronized(this){}

​类锁​

所有实例共享

Class对象

synchronized(Example.class){}

​关键区别​​:类锁会阻塞所有线程访问任何实例的同步静态方法。


​36. 进程和线程的区别及通信方式​

​答案:​

维度

进程

线程

​资源分配​

独立内存空间

共享进程资源

​切换开销​

高(需切换页表)

低(仅切换栈/寄存器)

​通信方式​

管道/信号量/共享内存/消息队列

wait()/notify()/Lock/Condition

​线程通信示例​​:

// 使用Condition

Lock lock = new ReentrantLock();

Condition condition = lock.newCondition();

condition.await(); // 阻塞

condition.signal(); // 唤醒


​37. 类锁和对象锁是否互斥?​

​答案:​
​不互斥​​。两者锁定不同的对象:

  • 类锁锁定的是Class对象(存储在方法区)
  • 对象锁锁定的是堆内存中的实例

​示例​​:

synchronized(Example.class) { /* 线程A */ }

synchronized(instance) { /* 线程B可同时执行 */ }


​38. 注解的作用目标​

​答案:​
​可作用的目标(通过@Target指定)​​:

  1. ​TYPE​​:类/接口/枚举
  2. ​FIELD​​:字段
  3. ​METHOD​​:方法
  4. ​PARAMETER​​:参数
  5. ​CONSTRUCTOR​​:构造器
  6. ​LOCAL_VARIABLE​​:局部变量

​示例​​:

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

public @interface Test {}


​39. 内部类的分类及场景​

​答案:​

类型

特点

使用场景

​成员内部类​

持有外部类引用

需要访问外部类成员时

​静态内部类​

不持有外部类引用

工具类/避免内存泄漏

​局部内部类​

定义在方法内

方法级封装

​匿名内部类​

无类名,即时实现

事件监听/临时实现接口

​内存泄漏风险​​:非静态内部类默认持有外部类引用,需谨慎使用。


​40. finally的作用及场景​

​答案:​
​核心作用​​:保证代码块必须执行(无论是否发生异常)

​典型场景​​:

  1. 资源释放(IO流/数据库连接)
  2. 锁释放(避免死锁)
  3. 日志记录

​注意​​:以下情况finally不会执行:

  • System.exit()
  • JVM崩溃
  • 守护线程被终止

​示例​​:

try {

    // 可能抛出异常的操作

} finally {

    lock.unlock(); // 确保锁释放

}


​41. 栈溢出 vs 堆溢出 vs 堆外内存​

​答案:​

类型

触发条件

错误表现

解决方案

JVM参数调整

​栈溢出​

递归调用过深

StackOverflowError

检查递归终止条件

-Xss调整栈大小

​堆溢出​

对象过多/内存泄漏

OutOfMemoryError

分析堆转储(MAT工具)

-Xmx/-Xms调整堆大小

​堆外内存​

NIO的DirectBuffer未释放

OutOfMemoryError

显式调用Cleaner

-XX:MaxDirectMemorySize

​内存区域图示:​


​42. Java集合类框架​

​答案:​
​核心接口分类:​

  1. ​Collection​
    1. List:ArrayList(数组)、LinkedList(链表)
    2. Set:HashSet(哈希表)、TreeSet(红黑树)
  2. ​Map​
    1. HashMap(数组+链表/红黑树)
    2. ConcurrentHashMap(分段锁/CAS)

​线程安全方案对比:​

Collections.synchronizedList(list); // 方法级锁

new CopyOnWriteArrayList<>(); // 写时复制

new ConcurrentHashMap<>(); // CAS+同步块


​43. 泛型实现与示例​

​答案:​
​泛型栈实现:​

public class GenericStack<T> {

    private T[] elements;

    private int top;

    

    @SuppressWarnings("unchecked")

    public GenericStack(int size) {

        elements = (T[]) new Object[size]; // 泛型数组创建

    }

    

    public void push(T item) {

        elements[top++] = item;

    }

    

    public T pop() {

        return elements[--top];

    }

}

​类型擦除验证:​

GenericStack<String> stack = new GenericStack<>(10);

System.out.println(stack.getClass()); // 输出class GenericStack(无类型参数)


​44. 反射获取私有信息的风险控制​

​答案:​
​获取私有字段的步骤:​

  1. 关闭安全检查提升性能:

Field field = clazz.getDeclaredField("secret");

field.setAccessible(true); // 突破private限制

  1. 操作完成后立即恢复访问控制:

AccessController.doPrivileged((PrivilegedAction<Void>) () -> {

    field.setAccessible(false);

    return null;

});

​安全建议:​

  • 配合SecurityManager使用
  • 避免在关键系统(如支付)滥用反射


​45. 线程状态转换​

​答案:​
​六种状态(Java.lang.Thread.State):​

  1. ​NEW​​:新建未启动
  2. ​RUNNABLE​​:可运行(包含就绪和运行中)
  3. ​BLOCKED​​:等待监视器锁
  4. ​WAITING​​:无限期等待(wait()/join())
  5. ​TIMED_WAITING​​:限期等待(sleep(1000))
  6. ​TERMINATED​​:执行完成

​状态转换图:​


​46. thread.start()后的状态变化​

​答案:​

Thread t = new Thread(() -> {});

System.out.println(t.getState()); // NEW

t.start();

System.out.println(t.getState()); // RUNNABLE

​底层机制:​

  1. JVM调用本地方法start0()
  2. 创建新调用栈,状态变为RUNNABLE
  3. 等待OS线程调度器分配CPU时间片


​47. 等待队列 vs 阻塞队列​

​答案:​

 在进入synchronized方法之前因为抢不到锁对象而进入阻塞状态,进入阻塞队列。进入到synchronized方法后由于调用了wait()方法而进入等待状态,此时进入等待队列,等待其它线程调用它的notify()方法将他唤醒。

特性

等待队列(Wait Queue)

阻塞队列(BlockingQueue)

​数据结构​

通过Object.wait()维护

显式队列(如ArrayBlockingQueue

​唤醒机制​

需显式调用notify()

自动唤醒(put/take操作)

​使用场景​

线程间通信

生产者-消费者模型

​阻塞队列示例:​

BlockingQueue<String> queue = new LinkedBlockingQueue<>(10);

queue.put("item"); // 阻塞直到空间可用

String item = queue.take(); // 阻塞直到元素可用


​48. sleep() vs wait()​

​答案:​

维度

sleep()

wait()

​锁释放​

不释放锁

释放锁

​调用位置​

任意位置

必须在同步块内

​唤醒方式​

超时自动唤醒

notify()/notifyAll()

​所属类​

Thread静态方法

Object实例方法


​49. sleep(1)的作用与场景​

​答案:​
​核心作用​​:主动让出CPU时间片至少1毫秒(实际取决于系统计时器精度)

​使用场景:​

  1. ​性能测试​​:消除线程竞争带来的误差

long start = System.nanoTime();

Thread.sleep(1); // 确保计时起点准确

// 被测代码

  1. ​竞态条件调试​​:放大并发问题出现概率
  2. ​节能控制​​:限制高频轮询的CPU占用

​注意事项​​:Windows系统最小休眠时间约15ms(受HPET影响)


​50. 中断机制与响应示例​

​答案:​
​中断三要素:​

  1. thread.interrupt():设置中断标志
  2. thread.isInterrupted():检查中断状态
  3. InterruptedException:阻塞方法响应中断

​示例:​

Thread worker = new Thread(() -> {

    while (!Thread.currentThread().isInterrupted()) {

        try {

            TimeUnit.SECONDS.sleep(1);

        } catch (InterruptedException e) {

            Thread.currentThread().interrupt(); // 重置中断状态

            System.out.println("优雅退出");

        }

    }

});

worker.start();

worker.interrupt(); // 触发中断

​中断处理最佳实践:​

  • 清理资源后重新设置中断状态
  • 避免屏蔽InterruptedException


​51. 守护线程 vs 协程​

​答案:​

特性

守护线程(Daemon Thread)

协程(Coroutine)

​调度层级​

操作系统级调度

用户态调度(语言/框架级)

​资源开销​

1MB+栈内存

KB级栈内存

​切换成本​

高(内核态切换)

极低(无系统调用)

​典型实现​

Java的Thread.setDaemon(true)

Kotlin协程/Quasar纤维

​应用场景​

后台日志收集

高并发IO操作(如10万+连接)

​守护线程示例:​

Thread daemon = new Thread(() -> {

    while (true) {

        // 执行监控任务

    }

});

daemon.setDaemon(true); // JVM退出时自动终止

daemon.start();


​52. 死锁条件与避免策略​

​答案:​
​四个必要条件:​

  1. 互斥条件:资源独占
  2. 占有且等待:持有资源并等待其他资源
  3. 不可剥夺:资源只能主动释放
  4. 循环等待:多个线程形成环形等待链

​避免方案:​

// 1. 破坏循环等待(按固定顺序获取锁)

public void transfer(Account from, Account to, int amount) {

    Account first = from.id < to.id ? from : to;

    Account second = from.id < to.id ? to : from;

    

    synchronized (first) {

        synchronized (second) {

            // 转账操作

        }

    }

}

// 2. 使用tryLock(破坏占有且等待)

if (lock1.tryLock(1, TimeUnit.SECONDS)) {

    try {

        if (lock2.tryLock(1, TimeUnit.SECONDS)) {

            try {

                // 临界区

            } finally {

                lock2.unlock();

            }

        }

    } finally {

        lock1.unlock();

    }

}


​53. 基本类型存储区域​

​答案:​
​存储规则:​

数据类型

存储区域

示例

局部变量

栈帧中的局部变量表

int i = 10;

实例字段

堆内存对象内

class A { int x; }

静态字段

方法区

static int y;

​特殊情况:​

  • 被final修饰的静态基本类型:存储在方法区的常量池
  • 数组类型:无论元素类型,数组对象本身在堆上分配


​54. 多线程使用场景​

​答案:​
​典型应用场景及实现:​

  1. ​高并发Web服务​

ExecutorService threadPool = Executors.newFixedThreadPool(200);

while (true) {

    Socket socket = serverSocket.accept();

    threadPool.execute(() -> handleRequest(socket));

}

  1. ​批量数据处理​

List<Data> dataList = getHugeData();

dataList.parallelStream().forEach(data -> process(data));

  1. ​异步任务调度​

CompletableFuture.supplyAsync(() -> fetchFromDB())

               .thenApplyAsync(data -> transform(data))

               .thenAcceptAsync(result -> sendToUI());

​选型建议:​

  • CPU密集型:线程数 = CPU核心数 + 1
  • IO密集型:线程数 = CPU核心数 * (1 + 平均等待时间/计算时间)


​55. throw vs throws​

​答案:​

维度

throw

throws

​作用位置​

方法内部

方法声明处

​功能​

主动抛出异常对象

声明可能抛出的异常类型

​语法​

throw new IOException("msg");

public void read() throws IOException

​处理要求​

必须立即处理或声明throws

调用方需处理或继续声明

​最佳实践:​

  • 检查异常(Checked Exception):用throws声明
  • 非检查异常(Unchecked Exception):通常不声明


​56. Object类方法解析​

​答案:​
​核心方法及作用:​

方法

功能说明

equals()

对象逻辑相等性比较(默认实现为==

hashCode()

返回对象哈希码(与equals()必须保持一致)

toString()

返回对象字符串表示(默认输出类名@哈希码)

wait()/notify()

线程间通信机制

getClass()

获取对象的运行时类(反射基础)

clone()

对象浅拷贝(需实现Cloneable接口)

finalize()

对象回收前的清理(JDK9已废弃)

​重写示例:​

@Override

public boolean equals(Object o) {

    if (this == o) return true;

    if (o == null || getClass() != o.getClass()) return false;

    User user = (User) o;

    return age == user.age && Objects.equals(name, user.name);

}

@Override

public int hashCode() {

    return Objects.hash(name, age); // 保证相同对象必有相同哈希值

}


​57. 总线锁优缺点​

​答案:​
​总线锁机制:​

  • ​作用​​:CPU通过LOCK#信号锁定总线,保证原子操作
  • ​应用场景​​:x86架构的volatile写操作、CAS指令

优点

缺点

实现简单,严格保证原子性

性能差(阻塞所有CPU访问内存)

适用于少量核心的CPU

多核环境下成为性能瓶颈

​现代替代方案​​:缓存一致性协议(MESI) + 缓存行锁定


​58. 多线程顺序输出控制​

​答案:​
​使用ReentrantLock+Condition实现:​

class PrintABC {

    private final Lock lock = new ReentrantLock();

    private final Condition[] conditions = new Condition[3];

    private int state = 0; // 0:A, 1:B, 2:C

    public PrintABC() {

        for (int i = 0; i < conditions.length; i++) {

            conditions[i] = lock.newCondition();

        }

    }

    public void print(int targetState, String str) {

        lock.lock();

        try {

            while (state % 3 != targetState) {

                conditions[targetState].await();

            }

            System.out.print(str);

            state++;

            conditions[state % 3].signal();

        } finally {

            lock.unlock();

        }

    }

}

// 启动线程

PrintABC printer = new PrintABC();

new Thread(() -> { while(true) printer.print(0, "A"); }).start();

new Thread(() -> { while(true) printer.print(1, "B"); }).start();

new Thread(() -> { while(true) printer.print(2, "C"); }).start();


​59. 懒汉式单例模式​

​答案:​
​双重检查锁定实现(线程安全):​

public class Singleton {

    private static volatile Singleton instance; // volatile禁止指令重排序

    private Singleton() {} // 私有构造

    public static Singleton getInstance() {

        if (instance == null) { // 第一次检查

            synchronized (Singleton.class) {

                if (instance == null) { // 第二次检查

                    instance = new Singleton();

                    // 对象初始化分为三步:

                    // 1. 分配内存 2. 初始化对象 3. 赋值引用

                    // volatile保证3不会重排序到2之前

                }

            }

        }

        return instance;

    }

}

​类加载时初始化(更简洁的方案):​

public class Singleton {

    private static class Holder {

        static final Singleton INSTANCE = new Singleton();

    }

    public static Singleton getInstance() {

        return Holder.INSTANCE; // 类加载时初始化,利用JVM类加载机制保证线程安全

    }

}


​60. Tomcat访问Controller原理​

​答案:​
​完整调用链路(500+字详解):​

​请求接收阶段​

    • Acceptor线程通过NIO监听端口,将连接注册到Poller线程
    • Poller通过Selector检测就绪事件,交给Worker线程池处理

​过滤器链处理​

// 伪代码展示FilterChain执行

public void doFilter(ServletRequest req, ServletResponse res) {

    for (Filter filter : filters) {

        filter.doFilter(req, res); // 执行Filter逻辑

    }

    // 最终到达Servlet

}

​Spring MVC集成​

    • DispatcherServlet初始化时创建:
      • HandlerMapping(路径到Controller的映射)
      • HandlerAdapter(实际调用Controller方法)
      • ViewResolver(视图解析)

​方法调用过程​

sequenceDiagram

    Tomcat->>DispatcherServlet: service()

    DispatcherServlet->>HandlerMapping: getHandler()

    HandlerMapping-->>DispatcherServlet: HandlerExecutionChain

    DispatcherServlet->>HandlerAdapter: handle()

    HandlerAdapter->>Controller: invokeMethod()

    Controller-->>HandlerAdapter: ModelAndView

    HandlerAdapter-->>DispatcherServlet: 返回结果

    DispatcherServlet->>ViewResolver: resolveViewName()

    ViewResolver-->>DispatcherServlet: View对象

    DispatcherServlet->>View: render()

​参数解析机制​

    • HandlerMethodArgumentResolver处理:
      • @RequestParam:从URL参数解析
      • @RequestBody:使用HttpMessageConverter反序列化
      • @PathVariable:从URI模板提取

​响应处理优化​

    • 使用AsyncContext实现异步响应:

@GetMapping("/async")

public void asyncHandle(HttpServletRequest req) {

    AsyncContext ctx = req.startAsync();

    CompletableFuture.runAsync(() -> {

        // 耗时操作

        ctx.getResponse().getWriter().write("Done");

        ctx.complete();

    });

}

​性能调优关键点:​

  • 调整server.tomcat.max-threads(默认200)
  • 启用NIO2协议:server.tomcat.protocol=org.apache.coyote.http11.Http11Nio2Protocol
  • 合理设置connectionTimeout(通常5000-10000ms)