面试官:第一轮提问,首先问你,Java 中的多线程有什么作用?
王铁牛:多线程可以提高程序的执行效率,能让程序同时执行多个任务。
面试官:回答得不错。那如何创建一个线程呢?
王铁牛:可以通过继承 Thread 类或者实现 Runnable 接口来创建线程。
面试官:很好。再问一个,线程池有什么优点?
王铁牛:线程池可以复用线程,减少线程创建和销毁的开销,提高性能。
面试官:进入第二轮提问。说说 HashMap 的底层数据结构。
王铁牛:HashMap 底层是数组+链表+红黑树的数据结构。
面试官:那 HashMap 在扩容时是怎么处理的?
王铁牛:嗯……就是重新计算哈希值,然后把元素放到新的位置。
面试官:回答得不是很清晰。最后一轮提问,Spring 框架中的 IOC 是什么?
王铁牛:IOC 就是控制反转,把对象的创建和依赖注入交给 Spring 容器。
面试官:那 AOP 又是什么?
王铁牛:AOP 是面向切面编程,能在不修改原有代码的基础上增强功能。
面试官:这次回答得也不太好。面试就先到这里,回去等通知吧。
答案:
- Java 中的多线程作用:多线程能提高程序执行效率,可让程序同时执行多个任务。比如在一个电商系统中,当有多个用户同时下单时,如果使用单线程,那么只能一个一个处理订单,效率很低。而使用多线程,就可以同时处理多个用户的下单请求,大大提高了系统的响应速度。
- 创建线程的方式:
- 继承 Thread 类:创建一个类继承 Thread 类,然后重写 run 方法,在 run 方法中编写线程要执行的任务。例如:
class MyThread extends Thread { @Override public void run() { System.out.println("线程执行的任务"); } } // 使用时 MyThread thread = new MyThread(); thread.start();- 实现 Runnable 接口:创建一个类实现 Runnable 接口,实现其中的 run 方法。然后创建 Thread 对象,将实现了 Runnable 接口的对象作为参数传递给 Thread 的构造函数。例如:
class MyRunnable implements Runnable { @Override public void run() { System.out.println("线程执行的任务"); } } // 使用时 MyRunnable runnable = new MyRunnable(); Thread thread = new Thread(runnable); thread.start(); - 线程池的优点:
- 复用线程:避免了频繁创建和销毁线程的开销。例如在一个高并发的 Web 服务器中,如果没有线程池,每处理一个请求就创建一个新线程,当请求量很大时,线程创建和销毁的开销会非常大。而使用线程池,线程可以被复用,处理完一个请求后不会销毁,而是等待下一个请求到来,大大提高了性能。
- 控制线程数量:可以根据系统的资源情况合理设置线程池的大小,避免过多线程消耗系统资源导致系统崩溃。
- HashMap 的底层数据结构:HashMap 底层是数组+链表+红黑树的数据结构。当哈希冲突较小时,数据存储在数组中;当哈希冲突较多时,相同哈希值的元素会形成链表;当链表长度超过一定阈值(默认为 8)时,链表会转换为红黑树,以提高查询效率。
- HashMap 扩容:当 HashMap 中的元素个数超过负载因子(默认 0.75)与容量的乘积时,就会触发扩容。扩容时,会创建一个新的更大的数组,然后重新计算每个元素的哈希值,将元素放入新数组中。这个过程涉及到重新计算哈希值和移动元素,比较复杂。
- Spring 框架中的 IOC(控制反转):IOC 就是把对象的创建和依赖注入交给 Spring 容器。比如在一个 Web 应用中,有一个 UserService 依赖于 UserDao。传统方式需要在 UserService 中手动创建 UserDao 对象。而使用 Spring 的 IOC,Spring 容器会负责创建 UserDao 对象,并将其注入到 UserService 中。这样做的好处是降低了组件之间的耦合度,方便代码的维护和扩展。
- Spring 框架中的 AOP(面向切面编程):AOP 是面向切面编程,能在不修改原有代码的基础上增强功能。例如在一个电商系统中,我们想要记录所有用户操作的日志。如果不使用 AOP,需要在每个业务方法中手动添加日志记录代码,这样会使代码变得很臃肿。而使用 AOP,可以定义一个切面,专门负责日志记录,然后将这个切面织入到需要记录日志的业务方法中,在不修改业务方法代码的情况下实现了日志记录功能,增强了系统的功能。