线程池

线程池是一种多线程处理的形式,通过把处理的任务添加到队列中,然后再创建线程后自动执行这些任务。线程池可以同时执行多个任务,如果任务队列已经满了,则新来的任务会进行排队等待。

优点

  • 线程池的重用减少了创建线程和销毁线程带来的性能开销。
  • 线程池对线程的数量可控,有效的降低了线程间的资源争夺情况。

线程池的参数

  • corePoolSize(核心线程数)
    在创建线程池后,线程池中没有任何线程,等到有任务的时候才会去创建线程,初始线程数是0,当线程池中的线程数目达到corePoolSize后,就会把任务放到阻塞队列里面去。核心线程会一直存活,即使是没有任务需要执行。(注:可以通过设置allowCoreThreadRimeOut = true , 使得核心线程空闲时间超时关闭) 当线程数小于核心线程数的时候,即使有线程空闲,线程池也会优先创建核心线程去运行直到等于核心线程数为止。
  • maximunPoolSize(最大线程数)
    表示当前线程池的最大线程数量,当阻塞队列满了之后,线程池会创建新线程来处理任务。当线程数等于最大线程数的时候,线程队列也满了的时候,线程池会拒绝处理任务而抛出异常。
  • keepAliveTime( 线程空闲时间)
    当线程超过空闲时间的时候,线程会关闭,直到线程数量等于核心线程数量。(注:当设置allowCoreThreadRimeOut = true , 核心线程空闲时间超时也会关闭
  • TimeUnit(空闲时间单位)
    空闲线程的保留的时间单位,取值:
    TimeUnit.DAYS; //天
    TimeUnit.HOURS; //小时
    TimeUnit.MINUTES; //分钟
    TimeUnit.SECONDS; //秒
    TimeUnit.MILLISECONDS; //毫秒
    TimeUnit.MICROSECONDS; //微妙
    TimeUnit.NANOSECONDS; //纳秒
  • ThreadFactory(线程工厂)
  • BlockingQueue< Runnable>(阻塞队列)
    阻塞队列分三种
    1. SynchronousQueue——直接提交策略
    适用于CachedThreadPool。它将任务直接提交给线程而不保持它们。如果不存在可用于立即运行任务的线程,则试图把任务加入队列将失败,因此会构造一个新的线程。此策略可以避免在处理可能具有内部依赖性的请求集时出现锁。直接提交通常要求最大的 maximumPoolSize 以避免拒绝新提交的任务(正如CachedThreadPool这个参数的值为Integer.MAX_VALUE)。当任务以超过队列所能处理的量、连续到达时,此策略允许线程具有增长的可能性。吞吐量较高。
    2. LinkedBlockingQueue——无界队列
    适用于FixedThreadPool与SingleThreadExcutor。基于链表的阻塞队列,创建的线程数不会超过corePoolSizes(maximumPoolSize值与其一致),当线程正忙时,任务进入队列等待。按照FIFO原则对元素进行排序,吞吐量高于ArrayBlockingQueue。
    3. ArrayListBlockingQueue——有界队列
    有助于防止资源耗尽,但是可能较难调整和控制。队列大小和最大池大小可能需要相互折衷:使用大型队列和小型池可以最大限度地降低 CPU 使用率、操作系统资源和上下文切换开销,但是可能导致人工降低吞吐量。如果任务频繁阻塞(例如,如果它们是 I/O边界),则系统可能为超过您许可的更多线程安排时间。使用小型队列通常要求较大的池大小,CPU使用率较高,但是可能遇到不可接受的调度开销,这样也会降低吞吐量。
  • RejectedExecutionHandler(任务拒绝处理器)
    1、线程池内部类处理:
    ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
    ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
    ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
    ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务
    2、两种情况会拒绝处理任务
  • 当线程数已经达到最大线程数,且队列已满,会拒绝信任务
  • 当线程池被调用shitdown()后,会等待线程池里的任务执行完毕,再shutdown.如果在调用shutdowm()线程池和线程池真正shutdown之间提交任务,会拒绝信任务。
    3、实现RejectedExecutionHandler接口,可自定义处理器。

四种线程池

1.newFixedThreadPool()

java线程池 核心线程会不会少 线程池 核心线程数 0_阻塞队列


固定线程数量的线程池,线程处于空闲时也不会被回收。这种线程池里只含有核心线程,也就意味着不会被系统回收,同时只要一有任务,newfixedthreadpool就会更加快速的去响应。

2.newCachedThreadPool()

java线程池 核心线程会不会少 线程池 核心线程数 0_阻塞队列_02


没有核心线程,不固定线程的数量,超时时长60秒,超过后会被回收,所以它的特性在空闲时,没有线程几乎是不占用内存的,适用于多量耗时少的任务。

3.newScheduledThreadPool(int corePoolSize)

java线程池 核心线程会不会少 线程池 核心线程数 0_创建线程_03

java线程池 核心线程会不会少 线程池 核心线程数 0_java线程池 核心线程会不会少_04


固定核心线程,主要用于定时任务或者周期性任务。

4.newSingleThreadExecutor()

java线程池 核心线程会不会少 线程池 核心线程数 0_阻塞队列_05


把所有任务统一在一个核心线程中顺序执行。

以上4种都是通过Executors 下面对应类型的方法来创建。