面试官:第一轮面试开始,首先问你,Java 中多线程有哪些实现方式?
王铁牛:嗯……有继承 Thread 类,还有实现 Runnable 接口。
面试官:回答正确。那线程池有哪几种创建方式?
王铁牛:有 newFixedThreadPool、newSingleThreadExecutor、newCachedThreadPool 这些。
面试官:不错。再问你,HashMap 在 JDK1.7 和 JDK1.8 中有哪些主要区别?
王铁牛:呃……这个,1.8 好像是改成红黑树了吧。
面试官:回答得不太准确,1.7 是数组+链表结构,1.8 是数组+链表+红黑树结构,当链表长度大于 8 且数组长度大于 64 时链表会转换为红黑树。
第一轮面试结束。
面试官:第二轮面试,Spring 中 Bean 的作用域有哪些?
王铁牛:有 singleton、prototype 等。
面试官:对。那 Spring Boot 如何进行配置文件的读取?
王铁牛:好像是用注解什么的,具体不太记得了。
面试官:Spring Boot 可以通过 @Value 注解读取配置文件中的属性。再问,MyBatis 中如何进行动态 SQL 语句的编写?
王铁牛:这个……用 标签之类的吧。
面试官:基本正确,还可以用 等标签。
第二轮面试结束。
面试官:第三轮面试,Dubbo 服务调用的原理是什么?
王铁牛:就是远程调用嘛。
面试官:回答太简单了,Dubbo 是通过注册中心、集群容错、负载均衡等机制来实现服务调用的。RabbitMq 如何保证消息的可靠性?
王铁牛:不太清楚。
面试官:比如可以通过持久化消息、确认机制等。最后问你,xxl-job 有哪些核心组件?
王铁牛:这个真不知道。
面试官:xxl-job 核心组件有调度中心、执行器等。本次面试结束,回去等通知吧。
答案:
- Java 多线程实现方式:
- 继承 Thread 类:通过继承 Thread 类并重写 run 方法来创建线程。
- 实现 Runnable 接口:实现 Runnable 接口的 run 方法,然后将其作为参数传递给 Thread 类的构造函数来创建线程。这种方式更适合多个线程共享资源的场景,因为 Java 不支持多重继承,实现 Runnable 接口可以避免这个限制。
- 线程池创建方式:
- newFixedThreadPool:创建一个固定大小的线程池,当提交的任务数超过线程池大小时,任务会在队列中等待,直到有线程空闲。
- newSingleThreadExecutor:创建一个单线程的线程池,任务会依次执行,保证顺序性。
- newCachedThreadPool:创建一个可缓存的线程池,如果线程池中有空闲线程则复用,没有则创建新线程,当线程空闲一段时间后会被回收。
- HashMap 在 JDK1.7 和 JDK1.8 区别:
- JDK1.7:是数组+链表结构。当向 HashMap 中插入元素时,首先计算元素的哈希值,然后通过哈希值找到对应的数组位置,如果该位置为空,则直接插入;如果不为空,则采用头插法将新元素插入到链表头部。
- JDK1.8:是数组+链表+红黑树结构。计算哈希值后找到数组位置,若为空则直接插入;若不为空,首先检查是否为链表,如果是链表且长度大于 8 且数组长度大于 64 时,链表会转换为红黑树,插入元素时按照红黑树的规则进行插入。当红黑树节点数小于等于 6 时,又会转换回链表。
- Spring 中 Bean 的作用域:
- singleton:单例模式,整个 Spring 容器中只有一个实例。
- prototype:原型模式,每次获取 Bean 时都会创建一个新的实例。
- request:在一次 HTTP 请求中有效。
- session:在一个 HTTP Session 中有效。
- globalSession:在一个全局的 HTTP Session 中有效(一般用于 Portlet 环境)。
- Spring Boot 读取配置文件: 可以通过 @Value 注解读取配置文件中的属性。例如在一个类中定义一个属性,然后在属性上使用 @Value("${属性名}") 注解,Spring Boot 会自动将配置文件中对应的属性值注入到该属性中。
- MyBatis 动态 SQL 语句编写:
- 标签:用于条件判断,根据条件决定是否包含某些 SQL 片段。例如:SQL 片段。
- 标签:用于循环遍历集合或数组。例如:SQL 片段,可以方便地处理批量插入、更新等操作。
- Dubbo 服务调用原理:
- 注册中心:服务提供者将自己的服务信息注册到注册中心,服务消费者从注册中心获取服务提供者的地址等信息。
- 集群容错:当有多个服务提供者时,Dubbo 会根据集群容错策略选择一个合适的提供者进行调用,如失败重试、负载均衡等。
- 负载均衡:Dubbo 提供了多种负载均衡策略,如随机、轮询、加权随机、加权轮询等,根据不同的场景选择合适的策略来分配请求到不同的服务提供者。
- RabbitMq 保证消息可靠性:
- 持久化消息:将消息持久化到磁盘,即使 RabbitMq 服务器重启,消息也不会丢失。可以通过设置队列和消息的持久化属性来实现。
- 确认机制:生产者发送消息后,可以通过确认机制知道消息是否成功到达 Broker。有两种确认方式,事务机制和发送方确认机制,发送方确认机制性能更好,通过设置 confirmCallback 来处理确认结果。
- 消费者确认:消费者接收消息后,可以通过手动确认或自动确认的方式告知 RabbitMq 消息已被处理。手动确认可以保证消息处理的可靠性,避免消息丢失或重复消费。
- xxl-job 核心组件:
- 调度中心:负责管理任务调度规则、触发调度等。是整个 xxl-job 的核心控制组件。
- 执行器:负责执行具体的任务。执行器可以部署在多个机器上,接收调度中心的任务并执行。
- 任务管理:包括任务的创建、编辑、删除等操作,在调度中心进行管理。
- 日志管理:记录任务执行的日志,方便查看任务执行情况。