【后端面经-java】java线程池满的处理策略

端面,java,线程,处理,策略 · 浏览次数 : 219

小编点评

**目录** 1. 线程池介绍 1.1 基本作用 1.2 处理流程 1.3 线程池大小设置 1.4 线程池参数 2. 线程池满的处理策略 2.1 默认--拒绝策略handler 2.2 丢弃某一线程,抛出异常 2.3 丢弃队列中最旧的任务,然后重新尝试执行任务 2.4 CallerRunsPolicy 3. 参考资料

正文

1. 线程池介绍

1.1 基本作用

对多个线程使用的资源进行集中管理。

  • 降低资源消耗:
    • 复用线程,降低线程创建和销毁造成的消耗;
  • 线程资源管理
    • 提高管理效率;
  • 提高线程的响应速度
    • 在线程池中随时等待被执行,CPU不用等到线程创建时间;

1.2 处理流程

当一个线程进入线程池之后,会进行如下的处理步骤:

  • 首先查看核心线程池是否满

    • 如果没满,线程将在此处等待被调度执行;
  • 如果核心线程池满了,那么查看队列是否满了

    • 如果没满,线程在这里等待进入核心线程池;
  • 如果队列也满了,那么查看临时线程池是否满了

    • 如果没满,创建临时线程来处理任务。
  • 如果临时线程池也满了,那就要根据2.线程池满的处理策略进行线程处理。
    如下图所示:
    在这里插入图片描述

当调度者需要调度一个线程的时候,按照如下步骤:

  • 核心线程池中获取一个线程,执行任务;
  • 如果线程处于等待态,获取下一个线程继续执行;
  • 某一个任务执行完毕后,线程返回就绪态而不是终止态,放入线程池中复用。

1.3 线程池大小设置

  • CPU操作密集的任务

    • 由于线程操作多半需要占据CPU资源,因此一个线程运行的过程中基本上很少会出现某一线程进入等待态而调度下一个线程的情况;
    • 因此CPU调度线程的速度偏慢,因此线程池大小不应过大,一般为CPU核心数+1;这样可以保证CPU的效率最高;
    • 如果线程池容量过大,那么不仅对CPU运行是一个很大的负担,而且大量线程都处于等待运行的阶段,等待时间过长,可能出现响应过慢的情况。
  • I/O操作密集的任务

    • 对于I/O操作密集的任务,线程对于CPU的资源占用常常被I/O等操作打断,此时线程进入等待态,CPU继续调度下一个线程;
    • CPU调度线程的速度偏快,线程池大小可以尽量大一点,这样能够保障CPU资源的利用率,提高线程执行效率;
    • 如果线程池容量过小,CPU在调度一段时间之后,所有线程都进入等待态,此时就会出现CPU空等的情况,不利于资源有效利用。
  • 注意

  • 对于就绪态等待态等线程状态和生命周期的介绍,可参考这篇博客

1.4 线程池参数

线程池的构造方法如下所示:

public ThreadPoolExecutor(int corePoolSize,
                        int maximumPoolSize,
                        long keepAliveTime,
                        TimeUnit unit,
                        BlockingQueue<Runnable> workQueue,
                        ThreadFactory threadFactory,
                        RejectedExecutionHandler handler);

线程池的创建包含以下参数:

  • corePoolSize:核心线程池容量大小
    • 如前文所述,线程进行核心线程池即可等待调度执行
  • maximumPoolSize:最大线程池大小
    • 通过这个来判断线程池是否已满。
      MaximumPoolSize = CorePoolSize + WorkQueue + 临时线程池大小
      
  • workQueue:任务队列
    • 无法进入核心线程池的线程将进入任务队列等待进入池中;
    • 阻塞队列对象,一般需要设定容量大小
  • keepAliveTime:线程存活时间
    • 线程池已满的情况下,空闲多余的线程有个存活时间,超过这个时间还没有进入核心线程池,那么将被丢弃;
  • timeUnit:线程存活时间单位
    • 配合线程存活时间使用;
  • handler:拒绝策略
    • 当前线程池满了之后(超过maxmumPoolSize),对于新的线程的处理策略,
    • 包括四种,在2.1 默认--拒绝策略handler有详细论述
  • threadFactory:线程工厂
    • 用于创建线程池中的线程。

2. 线程池满的处理策略

2.1 默认--拒绝策略handler

线程池满了之后,一般的处理方式是丢弃某一线程,并且抛出异常。
Handler有四种策略:

  • AbortPolicy:直接抛出异常RejectedExecutionException
  • DiscardPolicy:直接丢弃任务,但是不抛出异常( 默认)。
  • DiscardOldestPolicy:丢弃队列中最旧的任务,然后重新尝试执行任务;
  • CallerRunsPolicy:由调用线程处理该任务。

3. 参考资料

参考博客-1
参考博客-2
参考博客-3
参考博客-4

与【后端面经-java】java线程池满的处理策略相似的内容:

【后端面经-java】java线程池满的处理策略

本文对java线程池做了具体介绍,并且讨论了java线程池满了之后的拒绝策略。

【后端面经-Java】Java创建线程的方法简介

本文简要介绍了java中创建线程的四种方式,并介绍了线程概念,适合新手阅读。

【后端面经-Java】Java基本概念

【不定期更新】本文主要介绍了Java学习前期的一些概念问题,包括“面向对象和面向过程的区别”、“C++和Java的不同之处”等等,适合初学者学习。

【后端面经-Java】I/O多路复用 简录

本文主要介绍了Java当中常见的几种IO模型,介绍其运行机制和实际缺点,并进行技术对比,对于IO多路复用的实现方式进行分析。

【后端面经-Java】HashMap详解

本文详细介绍了hashmap,包括基本概念、hashmap数据结构、关键变量和重要方法,并且结合源码进行分析。

【后端面经-Java】Synchronize和ReentrantLock区别

本文介绍了Synchronize和ReentrantLock同步锁的相似和不同点,并指出两者的主要特点和适用场景。

【后端面经-Java】AQS详解

本文介绍了AQS的核心思想、基本架构、实现方法,并对框架中的重要源码方法进行介绍和分析

【后端面经-Java】公平锁和加锁流程

本文主要介绍了公平锁和非公平锁的概念和区别,并且结合Reentranslock锁的源码对加锁机制进行分析。

【后端面经-Java】JVM内存分区详解

本文主要介绍了JVM内存分区的基本情况,着重介绍了栈、堆、方法区的分区情况,并给出实际代码解释内存分配的过程。

【后端面经-Java】JVM垃圾回收机制

本文对JVM垃圾回收机制做了详细解释,从"where"、"which"、"when"、"why"、"how"、"who"的角度,重点介绍JVM垃圾回收机制的触发机制、垃圾判断算法、垃圾回收算法和垃圾回收机制。