线程池的学习

如下为我的的学习和总结,若是只是为了了解线程池,能够谷歌到大量优秀的文章.这里只是为了记录个人学习思路,参考的其余人的博客.,有些概括不正确之处望斧正 我会不断概括总结新看到的文章来丰富细节java

为何咱们要用线程池

除了用线程池代码看起来比较高大上这个理由外,先说说用线程池和不用线程池相比都有什么好处吧 我就用大白话解释了,总比复制粘贴死记硬背好些吧......数组

  • 下降资源消耗 建立和销毁线程是有成本消耗的.线程池正是为了解决线程生命周期开销问题和资源不足问题 经过重复利用已建立的线程下降线程建立和销毁形成的消耗。 这就像一次性筷子和食堂用的消毒筷子同样,不必每一个人吃完饭就把筷子销毁从新作(虽然实际上这样相对比较卫生......吧?)
  • 提升响应速度 当任务到达时,任务能够不须要等到线程建立就能当即执行。 仍是拿筷子解释吧(和食堂筷子卯上了),线程池就像装筷子的消毒柜,用时直接拿,用完再放回去.不必来我的吃饭(执行任务)就说:咱们在给你准备一双新筷子(建立新线程),你先等一下......
  • 提升线程的可管理性 线程是稀缺资源,若是无限制的建立,不只会消耗系统资源,还会下降系统的稳定性,使用线程池能够进行统一的分配,调优和监控。可是要作到合理的利用线程池,必须对其原理了如指掌。 消毒柜里统一发放用完后洗过(回收)的筷子(线程),而不是来我的就弄一双筷子,到最后筷子扔的处处都是

线程池的参数

会用线程池不就得了?为啥还要学那些乱七八糟的参数?贼复杂还很差背. 业务驱动技术,咱们在实际业务中可能须要到用到拥有不一样特性的线程池.废话很少说,先来DIY吧学习

  • corePoolSize(线程池的基本大小) 当提交一个任务到线程池时,线程池会建立一个线程来执行任务,即便其余空闲的基本线程可以执行新任务也会建立线程,等到须要执行的任务数大于线程池基本大小时就再也不建立。若是调用了线程池的prestartAllCoreThreads方法,线程池会提早建立并启动全部基本线程。 这里讲到了一个细节,核心线程能够用到就建立,也能够建立线程池时就直接建立好.这就比如行军打仗以前或行军中不断筹备粮饷,线程池也会根据策略尽快凑足线程个数,以备不时之需
  • runnableTaskQueue(任务队列) 用于保存等待执行的任务的阻塞队列。 若是执行的任务过多,线程池放不下,就会放到任务队列中. ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列,此队列按 FIFO(先进先出)原则对元素进行排序。 LinkedBlockingQueue:一个基于链表结构的阻塞队列,此队列按FIFO (先进先出) 排序元素,吞吐量一般要高于ArrayBlockingQueue。静态工厂方法Executors.newFixedThreadPool()使用了这个队列。 SynchronousQueue:一个不存储元素的阻塞队列。每一个插入操做必须等到另外一个线程调用移除操做,不然插入操做一直处于阻塞状态,吞吐量一般要高于LinkedBlockingQueue,静态工厂方法Executors.newCachedThreadPool使用了这个队列。 SynchronousQueue没有容纳元素的能力,即它的isEmpty()方法老是返回true,可是给人的感受却像是只能容纳一个元素。它模拟的功能相似于生活中一手交钱一手交货这种情形 PriorityBlockingQueue:一个具备优先级的无限阻塞队列。
  • maximumPoolSize(线程池最大大小):线程池容许建立的最大线程数。若是队列满了,而且已建立的线程数小于最大线程数,则线程池会再建立新的线程执行任务。值得注意的是若是使用了无界的任务队列这个参数就没什么效果。
  • ThreadFactory:用于设置建立线程的工厂,能够经过线程工厂给每一个建立出来的线程设置更有意义的名字。
  • RejectedExecutionHandler(饱和策略):当队列和线程池都满了,说明线程池处于饱和状态,那么必须采起一种策略处理提交的新任务。这个策略默认状况下是AbortPolicy,表示没法处理新任务时抛出异常。如下是JDK1.5提供的四种策略。 AbortPolicy(舍弃-抛出异常):直接抛出异常。 CallerRunsPolicy(调用者执行):只用调用者所在线程来运行任务。 DiscardOldestPolicy(丢弃最旧的):丢弃队列里最近的一个任务,并执行当前任务。 DiscardPolicy(丢弃):不处理,丢弃掉。 固然也能够根据应用场景须要来实现RejectedExecutionHandler接口自定义策略。如记录日志或持久化不能处理的任务。
  • keepAliveTime(线程活动保持时间):线程池的工做线程空闲后,保持存活的时间。因此若是任务不少,而且每一个任务执行的时间比较短,能够调大这个时间,提升线程的利用率。
  • TimeUnit(线程活动保持时间的单位):可选的单位有天(DAYS),小时(HOURS),分钟(MINUTES),毫秒(MILLISECONDS),微秒(MICROSECONDS, 千分之一毫秒)和毫微秒(NANOSECONDS, 千分之一微秒)。

参数比较多,但咱们要抓住重点去理解而不是死记硬背.线程池长啥样?简单描述就是个带着个阻塞队列的池子.固然它不是"死"的,它有本身解决特殊问题的各类的策略(饱和策略)线程

线程池的建立

new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, milliseconds,runnableTaskQueue, handler);rest

提交任务

有两种方式提交: execute 和 submit日志

  • execute方法没有返回值,因此没法判断任务是否被线程池执行成功。
  • submit 方法会返回一个future,能够经过这个future来判断任务是否执行成功,经过future的get方法来获取返回值,get方法会阻塞住直到任务完成,而使用get(long timeout, TimeUnit unit)方法则会阻塞一段时间后当即返回,这时有可能任务没有执行完。

线程池的关闭

shutdown或shutdownNow方法来关闭线程池 原理是遍历线程池中的工做线程,而后逐个调用线程的interrupt方法来中断线程,因此没法响应中断的任务可能永远没法终止。 shutdownNow首先将线程池的状态设置成STOP,而后尝试中止全部的正在执行或暂停任务的线程,并返回等待执行任务的列表 shutdown只是将线程池的状态设置成SHUTDOWN状态,而后中断全部没有正在执行任务的线程。code

线程池工做流程

线程池工做流程

线程池的处理流程以下:排序

首先线程池判断基本线程池是否已满?没满,建立一个工做线程来执行任务。满了,则进入下个流程。 其次线程池判断工做队列是否已满?没满,则将新提交的任务存储在工做队列里。满了,则进入下个流程。 最后线程池判断整个线程池是否已满?没满,则建立一个新的工做线程来执行任务,满了,则交给饱和策略来处理这个任务。接口

线程池的监控

经过线程池提供的参数进行监控。线程池里有一些属性在监控线程池的时候可使用 taskCount:线程池须要执行的任务数量。 completedTaskCount:线程池在运行过程当中已完成的任务数量。小于或等于taskCount。 largestPoolSize:线程池曾经建立过的最大线程数量。经过这个数据能够知道线程池是否满过。如等于线程池的最大大小,则表示线程池曾经满了。 getPoolSize:线程池的线程数量。若是线程池不销毁的话,池里的线程不会自动销毁,因此这个大小只增不+ getActiveCount:获取活动的线程数。生命周期

相关文章
相关标签/搜索