面试题答案
一键面试不同类型workQueue对拒绝策略触发条件的影响
- ArrayBlockingQueue:
- 是一个有界队列,其容量在构造时确定。
- 当队列已满,且线程池中的线程数已达到最大线程数时,新任务加入会立即触发拒绝策略。例如,若线程池核心线程数为5,最大线程数为10,ArrayBlockingQueue容量为20。当20个任务进入队列,且10个线程都在忙碌时,新任务就会触发拒绝策略。
- LinkedBlockingQueue:
- 可以是有界队列也可以是无界队列(默认无界)。
- 若是无界队列,理论上只要有新任务,都会放入队列,不会因为队列满而触发拒绝策略,只有当线程数达到最大线程数且所有线程都在忙碌,同时队列无限增长导致系统资源耗尽时,才可能触发拒绝策略(但实际应用中一般不会让队列无限增长)。例如,线程池核心线程数为5,最大线程数为10,使用无界的LinkedBlockingQueue,只要系统资源允许,任务会不断进入队列,不会因队列满触发拒绝策略。若使用有界的LinkedBlockingQueue,与ArrayBlockingQueue类似,当队列满且线程数达到最大线程数时触发拒绝策略。
实际应用中workQueue和拒绝策略组合的选择
- 任务处理优先级高,不允许丢失任务:
- 选择:可以使用ArrayBlockingQueue配合CallerRunsPolicy。
- 原因:ArrayBlockingQueue有界,能控制任务堆积数量。CallerRunsPolicy策略会让提交任务的线程自己执行任务,这样不会丢失任务,同时也能在一定程度上减轻线程池压力,例如在一些实时性要求高的金融交易处理场景,每个交易任务都很重要,不允许丢失。
- 允许一定任务丢失,追求高吞吐量:
- 选择:使用无界的LinkedBlockingQueue配合AbortPolicy。
- 原因:无界的LinkedBlockingQueue能尽量容纳任务,减少因队列满导致的拒绝。AbortPolicy在无法处理任务时直接抛出异常,适用于那些可以容忍部分任务失败,更注重整体处理效率的场景,比如日志记录任务,偶尔丢失几条日志记录对整体业务影响不大。
- 任务量波动大,需要控制资源消耗:
- 选择:有界的LinkedBlockingQueue配合DiscardOldestPolicy。
- 原因:有界队列能防止任务无限堆积消耗过多资源,DiscardOldestPolicy策略会丢弃队列中最老的任务,为新任务腾出空间,适用于任务处理能力有限,但任务量可能瞬间增大的场景,如一些小型服务器处理用户请求,当请求量突然增大时,优先处理新请求,丢弃旧的不太紧急的请求。