Java面试题经验总结

技术基础

多线程、线程池

如何创建多线程

  1. 继承Thread类
  2. 实现Runnable类
  3. 实现Callable类
  4. 实现线程池创建
  5. 使用匿名内部类

线程池的参数

  1. 核心线程数:定义了最小同时运行的线程数量;
  2. 最大线程数:当队列中的任务达到队列容量的时候,当前可以同时运行的线程数量变成最大线程数;
  3. 工作队列:当新任务来的时候会判断当前线程是否到达了核心线程数,如果达到了,就把新的任务放入工作队列中。
  4. 存活时间:当前线程池中的线程数量大于核心线程数量的时候,这个时候没有新的任务提交,核心线程外的线程不会立即被回收,而是等待到存活时间被销毁回收;
  5. 时间单位:存活时间的时间单位;
  6. 线程工厂:在创建线程时使用的工厂;
  7. 拒绝策略:当线程池关闭或者达到包河的状态时,新提交的任务会被拒绝;

任务队列

Java 提供了7种任务队列

  1. ArrayBlockingQueue:一个由数组结构组成的有界阻塞队列(数组结构可配合指针实现环形队列)。
  2. LinkedBlockingQueue:一个由链表结构组成的有界阻塞队列,在末指明容量时,容量默认值为最大值。
  3. PriorityBlockingQueue:一个支持优先级排序的无界阻塞队列,对元素没有要求,可以实现Comparable接口也可以提供Comparator来对队列的元素进行比较,跟时间没有任务关系,仅仅是按照优先级取任务;
  4. DelayQueue:类似于PriorityBlockingQueue,是二叉堆实现的无界优先阻塞队列。要求元素都实现delayed接口,通过执行时延从队列中提取任务,时间没到任务取不出;
  5. SynchronousQueue:一个不存储元素的阻塞队列,消费者线程调用take()方法的时候就发生阻塞,直到有一个生产者生产了一个元素,消费者线程就可以拿到这个元素并返回,生产者线程调用put()方法的时候也会发生阻塞,直到由一个消费者线程消费了一个元素,生产者才会返回。
  6. LinkedBlockingQueue:使用双向队列实现的有界双端阻塞队列,双端意味着可以像普通队列一直先进先出,也可以像栈一样先进后出;
  7. LinkedTransferQueue:它时ConcurrentLinkedQueue、LinkedBlockingQueue和SynchronousQueue的结合体,但是把它用在ThreadPoolExecutor中,和LinkedBlockingQueue行为一致,但是时无界的阻塞队列。

注意:有界队列和无界队列的区别是如果使用有界队列,当队列饱和的时候并超过最大线程数时就会执行拒绝策略;而如果使用的时无界队列,因为任务队列永远都可以添加任务,所以设置最大线程数没有任何意义;

拒绝策略

  1. AbortPolicy(默认):丢弃任务并抛出RejectedExecutionException异常;
  2. CallerRunsPolicy:由调用线程处理该任务;
  3. DiscardPolicy:丢弃任务,但是不抛出异常,可以配合这种模式进行自定义的处理方式。
  4. DiscardOldestPolicy:丢弃队列最早的未处理任务,如何重新尝试执行任务;

功能线程池

  • 定长线程池(FixedThreadPool)
    特点:只有核心线程,线程数量固定,执行立即回收,任务队列为链表结构的有界队列。
    应用场景:控制线程最大并发数。
  • 定时线程池(ScheduledThreadPool)
    特点:核心线程数量固定,非核心线程数量无限,执行完闲置10毫秒后回收,任务队列为延时阻塞队列。
    应用场景:执行定时或周期性任务。
  • 可缓存线程池(CachedThreadPool)
    特点:无核心线程,非核心线程数量无限,执行完闲置60秒后回收,任务队列为不存储元素的阻塞队列。
    应用场景:执行大量,耗时少的任务。
  • 单线程化线程池(SingleThreadPool)
    特点:只有一个核心线程,无非核心线程,执行完就立即回收,任务队列为链表结构的有界队列。
    应用场景:不适合并发单可能引起IO阻塞性及影响UI线程想要的操作,如数据库操作、文件操作等。

功能性线程池弊端为:

  1. FixedThreadPool 和 SingleThreadPool:主要的问题数堆积的请求处理队列采用LinkedBlockQueue,可能会消费非常大的内存,甚至导致OOM。
  2. CachedThreadPool 和 ScheduleThreadPool:主要问题是最大线程数数Integer.Max_VALUE,可能创建数量非常多的线程甚至导致OOM。

框架应用

SpringBoot自动配置

在项目启动的时候,SpringBoot去自动读取Meta-Info/spring.factories配置文件中EnableAutoConfiguration所配置的配置类,然后将其中所定义的bean根据条件注解所指定的条件来决定是否导入Spring容器中。

项目经验