面试官:请简要介绍一下 Java 中的多线程。
王铁牛:多线程就是在一个程序里同时执行多个任务嘛。比如一个程序既能处理用户输入,又能同时进行数据计算。
面试官:那说说线程池的原理和优势。
王铁牛:线程池就是预先创建一些线程,当有任务来的时候就从线程池里拿线程去执行任务。优势嘛,就是能减少线程创建和销毁的开销,提高性能。
面试官:HashMap 在多线程环境下会有什么问题?
王铁牛:哎呀,这个嘛,好像会有死循环啥的问题,具体不太清楚咋回事。
面试官:第一轮面试结束,回家等通知吧。
第一轮面试答案:
- 多线程:多线程是指在一个程序中可以同时执行多个任务的机制。在 Java 中,通过
Thread类或者实现Runnable接口来创建线程。多线程可以提高程序的响应性和资源利用率,例如在一个图形界面应用中,一个线程可以负责处理用户界面的交互,另一个线程可以在后台进行数据加载或计算,这样可以避免用户界面的卡顿。 - 线程池:线程池是一种预先创建一定数量线程的技术。其原理是当有任务提交时,从线程池中获取线程来执行任务,任务执行完毕后线程不会被销毁,而是继续留在线程池中等待下一个任务。优势在于减少了线程创建和销毁的开销,提高了系统性能和响应速度。比如在一个高并发的 Web 应用中,大量的请求会频繁创建和销毁线程,使用线程池可以避免这种开销,提高系统的处理能力。
- HashMap 多线程问题:在多线程环境下,HashMap 可能会出现死循环问题。这是因为在扩容时,HashMap 的链表结构可能会被打乱。当多个线程同时进行扩容操作时,可能会导致链表形成环形结构,从而在后续的查找操作中陷入死循环。例如,当一个线程在扩容链表时,另一个线程也在对链表进行操作,就可能导致链表结构异常,引发死循环。
面试官:讲讲 JVM 的内存模型。
王铁牛:JVM 内存模型就是有堆、栈、方法区这些呗。
面试官:JUC 包下常用的类有哪些?
王铁牛:有那个 CountDownLatch,还有啥来着,哦对,Semaphore。
面试官:ArrayList 在多线程下如何保证线程安全?
王铁牛:好像得用 Collections.synchronizedList() 方法把它变成线程安全的。
面试官:第二轮面试结束,回家等通知吧。
第二轮面试答案:
- JVM 内存模型:JVM 内存模型主要包括堆、栈、方法区、程序计数器等部分。堆是对象实例存储的地方;栈用于存储局部变量、方法调用等信息;方法区存储类信息、常量、静态变量等;程序计数器记录当前线程执行的字节码指令地址。例如,当一个对象被创建时,它会在堆中分配内存空间。方法在执行时,其局部变量会在栈中分配。对于类的加载信息、常量等则存储在方法区。
- JUC 包下常用类:
- CountDownLatch:用于线程间的同步,它允许一个或多个线程等待其他一组线程完成操作。例如,在一个多线程任务中,主线程可以创建一个 CountDownLatch,并设置计数值为 N,然后多个子线程开始执行任务,当每个子线程完成任务后,调用 CountDownLatch 的 countDown() 方法,将计数值减 1,当计数值减为 0 时,等待在 CountDownLatch 上的主线程就会被唤醒继续执行。
- Semaphore:信号量,用于控制对共享资源的访问。它维护了一个许可集,线程在访问共享资源前需要获取许可,访问完成后释放许可。比如在一个停车场系统中,可以使用 Semaphore 来控制停车位的数量,当有车进入停车场时,获取一个许可,当车离开时,释放许可。
- ArrayList 线程安全:ArrayList 本身不是线程安全的。要保证线程安全,可以使用 Collections.synchronizedList() 方法将其包装成一个线程安全的 List。例如:
List<String> synchronizedList = Collections.synchronizedList(new ArrayList<>());这样在多线程环境下对该 List 的操作就会是线程安全的,因为该方法内部通过使用一个锁对象来同步对 List 的访问,避免了多线程同时修改 List 导致的数据不一致问题。
面试官:Spring 的核心特性有哪些?
王铁牛:Spring 能做依赖注入,还有面向切面编程。
面试官:Spring Boot 与传统 Spring 相比有哪些优势?
王铁牛:Spring Boot 好像更简单,配置少,能快速搭建项目。
面试官:MyBatis 的工作原理是什么?
王铁牛:就是通过 XML 配置文件或者注解来映射 SQL 语句,把数据从数据库取出来。
面试官:第三轮面试结束,回家等通知吧。
第三轮面试答案:
- Spring 的核心特性:
- 依赖注入(Dependency Injection):通过控制反转(IoC)的方式,将对象的依赖关系由程序主动创建改为由容器注入,降低了组件之间的耦合度。例如,一个业务类可能依赖于一个数据访问类,在 Spring 中,容器会自动将数据访问类的实例注入到业务类中,而不是业务类自己去创建。
- 面向切面编程(Aspect Oriented Programming,AOP):允许将一些通用的功能(如日志记录、事务管理等)与业务逻辑分离,以提高代码的可维护性和复用性。比如,可以通过 AOP 配置,在方法执行前后自动记录日志,而不需要在每个业务方法中手动编写日志代码。
- Spring Boot 与传统 Spring 相比的优势:
- 简化配置:Spring Boot 采用了自动配置的机制,大大减少了繁琐的 XML 配置文件。开发人员只需要关注业务逻辑,而不需要花费大量时间在配置上,提高了开发效率。例如,对于一个基于 Spring Boot 的 Web 应用,只需要添加少量的依赖和注解,就可以快速搭建起一个完整的 Web 服务。
- 快速搭建项目:Spring Boot 提供了各种 Starter 依赖,通过引入这些 Starter,可以快速集成各种功能,如数据库访问、安全认证等。开发人员可以使用
spring-boot-starter-web快速创建一个 Web 项目,使用spring-boot-starter-data-jpa快速集成 JPA 进行数据库操作。
- MyBatis 的工作原理:
- SQL 映射:MyBatis 通过 XML 配置文件或注解来定义 SQL 语句与 Java 对象之间的映射关系。例如,在 XML 配置文件中,可以定义一个
<select>标签,指定 SQL 查询语句,并通过resultMap或resultType来指定查询结果如何映射为 Java 对象。 - 执行流程:当执行 SQL 操作时,MyBatis 首先读取配置文件中的 SQL 映射信息,然后根据传入的参数,动态生成 SQL 语句。接着,MyBatis 通过 JDBC 与数据库进行交互,执行 SQL 语句并获取结果。最后,将结果按照配置的映射规则转换为 Java 对象返回给调用者。比如,当调用一个 MyBatis 的查询方法时,它会根据配置找到对应的 SQL 语句,填充参数后执行查询,再将查询结果封装成指定类型的 Java 对象返回。
- SQL 映射:MyBatis 通过 XML 配置文件或注解来定义 SQL 语句与 Java 对象之间的映射关系。例如,在 XML 配置文件中,可以定义一个