面试官:请简要介绍一下 Java 中的多线程,以及如何创建一个线程。
王铁牛:多线程就是在一个程序中同时运行多个线程嘛。创建线程可以通过继承 Thread 类或者实现 Runnable 接口。
面试官:不错,回答得挺简洁明了。那再说说线程池吧,线程池有什么作用?
王铁牛:线程池可以复用线程,减少线程创建和销毁的开销,提高性能。
面试官:很好。那 HashMap 在多线程环境下有什么问题?
王铁牛:呃……这个嘛,好像会有死循环啥的问题。
面试官:第二轮开始。说说 JVM 的内存模型。
王铁牛:JVM 内存模型包括堆、栈、方法区这些……
面试官:具体讲讲堆内存的分区。
王铁牛:嗯……有新生代、老年代、永久代吧。
面试官:永久代现在在 JDK 1.8 之后叫什么了?
王铁牛:这……我不太确定。
面试官:第三轮。Spring 框架的核心特性有哪些?
王铁牛:Spring 嘛,依赖注入、面向切面编程……
面试官:Spring Boot 自动配置原理是什么?
王铁牛:这个……我不太清楚。
面试官:好了,今天的面试就到这里,回去等通知吧。
答案:
- 多线程及创建线程:多线程是指在一个程序中同时运行多个线程,以实现并发执行任务。创建线程可以通过继承 Thread 类并重写 run 方法,或者实现 Runnable 接口的 run 方法,然后通过 Thread 类的构造函数传入 Runnable 对象来创建线程。例如:
- 继承 Thread 类:
class MyThread extends Thread { @Override public void run() { System.out.println("This is a thread."); } } MyThread thread = new MyThread(); thread.start();- 实现 Runnable 接口:
class MyRunnable implements Runnable { @Override public void run() { System.out.println("This is a runnable thread."); } } Thread thread = new Thread(new MyRunnable()); thread.start(); - 线程池的作用:线程池可以复用线程,减少线程创建和销毁的开销,提高性能。它可以控制线程的数量,避免过多线程导致系统资源耗尽。例如,在处理大量并发请求时,如果不使用线程池,每个请求都创建一个新线程,会消耗大量系统资源。使用线程池可以预先创建一定数量的线程,当有请求到来时,从线程池中获取线程来处理请求,处理完后线程不会被销毁,而是放回线程池供下次使用。
- HashMap 在多线程环境下的问题:在多线程环境下,HashMap 可能会出现死循环问题。这是因为在扩容时,HashMap 的链表可能会形成环形结构。当多个线程同时进行扩容操作时,可能会导致链表结构被破坏,形成环形链表。当后续有线程访问该链表时,就会陷入死循环。例如,在 JDK 1.7 中,HashMap 的扩容机制是先创建一个新的数组,然后将原数组的元素重新计算位置后放入新数组。在多线程环境下,可能会出现部分元素还未完全移动到新数组,而其他线程又开始对新数组进行操作,从而导致链表形成环形结构。
- JVM 的内存模型:JVM 内存模型包括堆、栈、方法区等。堆内存是 JVM 中最大的一块内存区域,主要用于存储对象实例。它又分为新生代、老年代和永久代(JDK 1.8 之后为元空间)。新生代主要用于存储新创建的对象,采用复制算法进行垃圾回收。老年代存储经过多次垃圾回收后仍然存活的对象,采用标记清除或标记整理算法进行垃圾回收。永久代(元空间)主要存储类信息、常量池等。
- Spring 框架的核心特性:
- 依赖注入(Dependency Injection):通过容器将对象之间的依赖关系注入到对象中,而不是在对象内部自行创建依赖对象,这样可以提高对象的可维护性和可测试性。
- 面向切面编程(Aspect Oriented Programming,AOP):允许将横切关注点(如日志记录、事务管理等)与业务逻辑分离,通过切面织入到业务逻辑中,实现代码的复用和关注点的分离。
- IoC 容器:负责创建、配置和管理对象之间的依赖关系,使得对象之间的耦合度降低,便于代码的维护和扩展。
- Spring Boot 自动配置原理:Spring Boot 自动配置是基于条件注解实现的。它通过 @Conditional 系列注解来判断当前环境是否满足特定条件,如果满足条件,则自动配置相应的 Bean。例如,当项目中引入了 Spring Data JPA 依赖时,Spring Boot 会自动配置 JPA 的相关 Bean,如 EntityManagerFactory、TransactionManager 等。这是因为 Spring Boot 中有一系列的自动配置类,这些自动配置类会根据类路径下的依赖和当前环境的配置来决定是否配置某个 Bean。通过这种方式,Spring Boot 可以根据项目的实际需求自动配置大部分的基础设施,大大简化了项目的开发。