JAVA中的线程池

来源:互联网 发布:unity3d项目实战教程 编辑:程序博客网 时间:2024/06/05 15:31

———————–本文参考《JAVA并发编程的艺术》和JDK1.8。—————

JAVA中的线程池是运用场景最多的并发框架,几乎所有需要异步或并发执行的任务的程序都可以使用线程池。
->《JAVA并发编程的艺术》

1.线程池的好处

  • 降低线程创建和销毁造成的资源损耗。
  • 提高响应速度:任务到达时,可以装载到线程中执行,而不必等到线程创建完毕。
  • 提高线程的可管理性:使用线程池可以进行统一分配、调优和监控。
  • 控制最大并发数,避免阻塞。

2.线程池的实现原理

当使用者向线程池提交一个任务之后,线程池的处理流程如下:

这里写图片描述

这里我来解释一下:

在线程池中,存在一个内部的核心线程池,核心线程池中的线程是任务执行的核心干将,既然他们是“干将”那么我们有任务肯定有限将任务交给这些线程。当任务到达,我们先去查询核心线程池中的线程(“干将”)是否都有任务在身并且“干将”的数目达没达到指定数目,如果核心线程的数目未到指定数目,那么就创建新的核心线程来执行任务;如果不满足上述条件,再去判断阻塞队列是否已满,如果未满,那么将任务打入队列;如果队列满了,那么去判断“小兵”(线程池中的非核心线程)是否数目足够了,如果没有则创建线程,如果够了那么执行一定的策略。

ThreadPoolExecutor采取上述步骤的整体设计思路,是为了在执行execute()方法时,尽可能的避免获取全局锁(那将会是一个严重的可伸缩瓶颈)。在ThreadPoolExecutor完成预热之后(即当前运行的线程数大于等于corePoolSize值),几乎所有的executer()方法调用都是调用步骤2,而步骤2不需要获取全局锁。

从源码简单看线程池的工作原理:

线程池创建线程时,会将线程封装成工作线程worker,worker在执行完任务后,还会循环获取工作队列内的任务来执行。

3.线程池的使用

⑴:线程池的创建

这里我们先简单点了解一下关于线程池内部的一些主要参数,具体的分析以后会在源码解析里面详细解释一下。

①corePoolSize:线程池的基本大小,即核心干将的数量上限。当提交一个任务到线程池时,线程池会创建一个线程来执行任务,即使其他空闲的基本线程能够执行新任务也会创建该类线程,等到执行的任务书大于线程池基本大小时就不在创建。

②runnableTaskQueue:任务队列,用于保存等待执行的任务的阻塞队列,又分为基于链表结构的队列,基于数组结构的队列,具有优先级的无限阻塞队列等。

③maxinumPoolSize:线程池的最大数量,也就是线程池可以创建的线程的最大数,如果使用了无界的任务队列这个参数就没有什么效果。

④ThreadFactory:用于设置创建线程的工厂。

⑤RejectedExecutionHandler:饱和策略,线程池不能承载任务时采用的处理多余任务的方式,有抛出异常、丢弃队列里最近的一个任务并执行当前任务、不处理并且丢弃任务等策略。

⑵:向线程池提交任务

可以使用2个方法,execute()和submit()。

execute()用于提交无返回值的任务,submit()用于提交有返回值的任务。

⑶:关闭线程池

2个方法,shutdown()和shutdownNown()。它们的普遍原理是遍历线程池中的工作线程,然后逐个调用线程的interrupt方法来中断线程。

shutdown()会中断所有没有正在执行任务的线程,shutdownNown()会关闭所有线程,而不会管任务是否执行完毕。

4.线程池的监控

监控线程池的时候可以使用下面几个属性:

1.taskCount:线程需要执行的任务数目。

2.completedTasdCount:线程池在运行过程中已完成的任务数量,小于或者等于taskCount。

3.targestPoolSize:线程池中曾经存在的线程的最大数量。通过该属性可以知道线程池是否满过。

4.getPoolSize:线程池内的线程数量。如果线程池不销毁,线程池里的线程不会自动销毁,所以该属性只增不减

5.getActiveCount:获取活动的线程数。

总结:本文只是简要介绍了一下JAVA中的线程池有关概念,接下来的博文中我会结合实际Demo着重介绍线程池具体的使用

0 0
原创粉丝点击