天天看点

浅析线程池 ---Java并发编程的艺术(八)线程池线程池的实现原理

线程池

  • 线程池
  • 线程池的实现原理
    • 饱和策略
    • 几个核心参数
    • java中提供的线程池
    • execute()和submit()方法

线程池

Java中的线程池是运用场景最多的并发框架,几乎所有需要异步或并发执行任务的程序都可以使用线程池

什么是线程池

线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。

为什么要使用线程池

  • 降低资源消耗,通过重复利用已创建的线程降低线程创建和销毁造成的消耗
  • 提高响应速度,当任务到达时,任务可以不需要等到线程创建就能立即执行
  • 提高线程的可管理性,程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一分配、调优和监控

线程池的实现原理

线程池是如何处理任务的呢?

1)线程池判断核心线程池里的线程是否都在执行任务。如果不是,则创建一个新的工作线程来执行任务。如果核心线程池里的线程都在执行任务,则进入下个流程。

2)线程池判断工作队列是否已经满。如果工作队列没有满,则将新提交的任务存储在这个工作队列里。如果工作队列满了,则进入下个流程。

3)线程池判断线程池的线程是否都处于工作状态。如果没有,则创建一个新的工作线程来执行任务。如果已经满了,则交给饱和策略来处理这个任务。

浅析线程池 ---Java并发编程的艺术(八)线程池线程池的实现原理

如果看不懂,可以看下面这个图

浅析线程池 ---Java并发编程的艺术(八)线程池线程池的实现原理

饱和策略

RejectedExecutionHandler(饱和策略):当队列和线程池都满了,说明线程池处于饱和状态,那么必须采取一种策略处理提交的新任务。这个策略默认情况下是AbortPolicy,表示无法处理新任务时抛出异常

  • AbortPolicy:直接抛出异常。
  • CallerRunsPolicy:只用调用者所在线程来运行任务
  • DiscardOldestPolicy:丢弃队列里最近的一个任务,并执行当前任务。
  • DiscardPolicy:不处理,丢弃掉

几个核心参数

  • corePoolSize corePoolSize(线程池的基本大小):当提交一个任务到线程池时,线程池会创建一个线程来执行任务,即使其他空闲的基本线程能够执行新任务也会创建线程,等到需要执行的任务数大于线程池基本大小时就不再创建。如果调用了线程池的prestartAllCoreThreads()方法,线程池会提前创建并启动所有基本线程。
  • runnableTaskQueue (任务队列):用于保存等待执行的任务的阻塞队列。可以选择以下几

    个阻塞队列。

    • ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列,此队列按FIFO(先进先出)原

      则对元素进行排序

    • LinkedBlockingQueue:一个基于链表结构的阻塞队列,此队列按FIFO排序元素,吞吐量通

      常要高于ArrayBlockingQueue。静态工厂方法Executors.newFixedThreadPool()使用了这个队列。

    • SynchronousQueue:一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用

      移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于Linked-BlockingQueue,静态工

      厂方法Executors.newCachedThreadPool使用了这个队列

    • ·PriorityBlockingQueue:一个具有优先级的无限阻塞队列。
  • keepAliveTime(线程活动保持时间) 线程池的工作线程空闲后,保持存活的时间。所以,如果任务很多,并且每个任务执行的时间比较短,可以调大时间,提高线程的利用率。
  • TimeUnit(线程活动保持时间的单位) 可选的单位有天(DAYS)、小时(HOURS)、分钟(MINUTES)、毫秒(MILLISECONDS)、微秒(MICROSECONDS,千分之一毫秒)和纳秒(NANOSECONDS,千分之一微秒)。

java中提供的线程池

Executors类提供了4种不同的线程池:

1、newCachedThreadPool:用来创建一个可以无限扩大的线程池,适用于负载较轻的场景,执行短期异步任务。(可以使得任务快速得到执行,因为任务时间执行短,可以很快结束,也不会造成cpu过度切换)

2、newFixedThreadPool:创建一个固定大小的线程池,因为采用无界的阻塞队列,所以实际线程数量永远不会变化,适用于负载较重的场景,对当前线程数量进行限制。(保证线程数可控,不会造成线程过多,导致系统负载更为严重)

3、newSingleThreadExecutor:创建一个单线程的线程池,适用于需要保证顺序执行各个任务。

4、newScheduledThreadPool:适用于执行延时或者周期性任务。

execute()和submit()方法

1、execute(),执行一个任务,没有返回值。

2、submit(),提交一个线程任务,有返回值。

前几天就看完了,一值懒得总结,今天晚上加加班,写完前几天复习完的,加油加油!