前几天我和我的小伙伴在做软件杯大的才赛题目作品的时候使用到了线程。其中有一个一边运行其他程序一边要计时来判断是否让其他程序停止或开始运行。但是我弄了两天,并没有弄出来,或者说弄出来的效果特别不好。最近我看了《解密线程池工作原理》使我收获很多。
线程池是怎么由来的呢?线程也是一种宝贵的资源,并且也是一种有限的资源,创建和销毁线程也同样需要付出不菲的代价。我们所有的代码都是由一个一个的线程支撑起来的,比如说java中的main函数就是一个线程。为了解决高效的管理多线程之间的分工与协作,Doug Lea 大神为我们设计并实现了一款线程池工具,通过该工具就可以实现多线程的能力,并实现任务的高效执行与调度。作者主要从三个方面来对线程池进行分析:线程池状态、重要属性、工作流程。
1.线程池状态
线程状态是标识这线程池内部的一些运行情况,线程池的开启到关闭的过程就是线程池状态的一个流转的过程。线程池一共有五种状态:
状态 |
含义 |
RUNNING |
运行状态,该状态下线程池可以接受新的任务,也可以处理阻塞队列中的任务 |
SHUTDOWN |
待关闭状态,不再接受新的任务,继续处理阻塞队列中的任务 |
STOP |
停止状态,不接收新任务,也不处理阻塞队列中的任务,并且会尝试结束执行中的任务 |
TIDYING |
整理状态,此时任务都已经执行完毕,并且也没有工作线程 |
TERMINATED |
终止状态,此时线程池完全终止了,并完成了所有资源的释放 |
- 重要属性
程池一共有5种重要属性:线程状态和工作线程数量,核心线程数和最大线程数,创建线程的工厂,缓存任务的阻塞队列,非核心线程存活时间,拒绝策略。
(1)线程状态在那个太就是上面所说的,工作线程数量是要保存当前线程池中工作线程的个数。
(2)核心线程数是指corePoolSize 用来表示线程池中的核心线程的数量,也可以称为可闲置的线程数量。最大线程数是指maximumPoolSize 用来表示线程池中最多能够创建的线程数量。
(3)创建线程是由线程工厂 ThreadFactory 来完成创建线程,并绑定该任务,直到工作线程的数量达到 corePoolSize 前都不会重用之前的线程。
(4)当工作线程数达到 corePoolSize 了,这时又接收到新任务时,会将任务存放在一个阻塞队列中等待核心线程去执行。为什么不直接创建更多的线程来执行新任务呢,原因是核心线程中很可能已经有线程执行完自己的任务了,或者有其他线程马上就能处理完当前的任务,并且接下来就能投入到新的任务中去,所以阻塞队列是一种缓冲的机制,给核心线程一个机会让他们充分发挥自己的能力。另外一个值得考虑的原因是,创建线程毕竟是比较昂贵的,不可能一有任务要执行就去创建一个新的线程。
(5)阻塞队列又两种情况:一种是有界的队列,一种是无界的队列。如果是无界队列,那么当核心线程都在忙的时候,所有新提交的任务都会被存放在该无界队列中,这时最大线程数将变得没有意义,因为阻塞队列不会存在被装满的情况。如果是有界队列,那么当阻塞队列中装满了等待执行的任务,这时再有新任务提交时,线程池就需要创建新的“临时”线程来处理,相当于增派人手来处理任务。但是创建的“临时”线程是有存活时间的,不可能让他们一直都存活着,当阻塞队列中的任务被执行完毕,并且又没有那么多新任务被提交时,“临时”线程就需要被回收销毁,在被回收销毁之前等待的这段时间,就是非核心线程的存活时间.
(6)虽然我们有了阻塞队列来对任务进行缓存,这从一定程度上为线程池的执行提供了缓冲期,但是如果是有界的阻塞队列,那就存在队列满的情况,也存在工作线程的数据已经达到最大线程数的时候。如果这时候再有新的任务提交时,显然线程池已经心有余而力不足了,因为既没有空余的队列空间来存放该任务,也无法创建新的线程来执行该任务了,所以这时我们就需要有一种拒绝策略.
- 工作流程
通过阅读这篇文章,我了解了线程池的工作原理,主要了解线程池的状态,重要属性以及工作流程。以后在学习种使用线程应该会更加熟悉一些。