温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Java线程池是怎么实现的

发布时间:2021-08-27 16:33:13 来源:亿速云 阅读:130 作者:chen 栏目:编程语言

这篇文章主要介绍“Java线程池是怎么实现的”,在日常操作中,相信很多人在Java线程池是怎么实现的问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java线程池是怎么实现的”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

  Java 线程池怎么玩

  想玩明白 Java 的线程池,只需要的知道构建线程池的几个参数具体的含义基本上就明了了。那么接下来,就让我们一一瓦解这些参数。

  corePoolSize

  我们假设有 N 个任务需要提交到线程池去处理,当任务数量 N 小于核心线程数 corePoolSize(后文用 C 来代替) 的时候,线程池会不断新建线程来处理用户提交进来的任务即使有线程空闲。C 其实代表的是线程池通常情况下会保留的线程数量(如果将线程池比作一个工厂,C 可以类比为工厂的正式编制人员数量),当任务数量 N 超过核心线程数量 C 的时候,线程池就要用到下一个参数 workQueue 了。

  workQueue

  当用户提交的任务数量变多了,这时候线程池中的线程数量已经达到核心线程数 C,那么只能将提交过来的任务暂存在 workQueue 队列中。每当有线程处理完手头上活的时候就会来工作队列领取任务,如果队列中没有任务,那么当前线程就阻塞在队列上,等待任务。工作队列可以简单分为 2 种:无界队列和有界队列。

  无界队列

  如果我创建线程池的传入的是无界队列,那么意味着用户可以源源不断的提交任务到线程池,而不需要担心线程池拒绝接收,例如 LinkedBlockingQueue 就是一种选择。

  有界队列

  如果我们传入的是有界队列,例如 ArrayBlockingQueue,那就需要考虑队列存满了怎么办?不用担心这个时候线程池会帮忙找一些临时工来干活,这就需要用到下一个参数 maximumPoolSize 了。

  maximumPoolSize

  此时所有的核心线程都在干活,而且工作队列也存满了任务。如果还是有任务提交进来,那么线程池会再创建新的线程来帮助工作(可以类比为一个工厂,管理员发现任务太多,仓库也堆满了任务需要雇佣一些临时工来帮助干活)。当然临时工也不能雇佣太多,毕竟工厂资源有限,需要设定工厂里面工人最大上限,这个就是 maximumPoolSize 了。然而疯狂的用户哪管你能不能处理完任务,还是不断的提交任务进来,这个时候线程池忍无可忍了,关门拒绝用户提交新的任务,这时候 RejectedExexcutionHandler 就要开始发挥作用了。

  RejectedExexcutionHandler

  线程池共提供了如下 4 种拒绝策略AbortPolicy 策略会抛出一个 RejectedExecutionException 异常给用户,告诉它任务被拒绝了。DiscardPolicy 策略当任务来临时候不会给用户任何反馈,悄无声息拒绝任务。DiscardOldestPolicy 策略比较霸道,它会直接将最早存储在工作队列的任务丢弃掉,然后再试图去执行当前提交进来的任务。CallerRunsPolicy 策略呢虽然线程池中的工人不帮忙处理任务了,它会占用用户线程去处理当前任务,这也就意味着用户线程要处理完当前任务才可以做其他事情。

  使用上面的几个核心参数完美的解决了任务的提交流程和工作分配问题,接下来就要来考虑一下后面的工作了。用户提交了一大波任务以后,就不在提交了。这时候线程池的中工人都还在呢,如果一直保留这些资源但是又没有活干,会造成资源的浪费。这时候就需要用到 keepAliveTime 和 TimeUnit 参数了。

  keepAliveTime 和 TimeUnit

  这 2 个参数组合起来决定了一个工人最多可以在工厂里愉快的摸鱼时间,如果摸鱼时间超过这个限度,这个工人资源就会被释放,也就是这个空闲线程资源就被回收掉咯。当然啦,线程池会保留核心线程在工厂里面等待新任务,以备有新任务的到来,我们也可以通过 public void allowCoreThreadTimeOut(boolean value) 方法设置参数,来允许线程池也可以释放核心线程。

  threadFactory

  还剩下最后一个参数,它比较简单,主要用来创建线程,例如我们想让线程池中的线程做一些定制化的工作就可以自己来定义线程工厂,这样线程池创建线程的时候就使用我们指定的工厂了。

  你可能会觉得构建一个线程还要设置这么参数,太麻烦了,贴心的 JDK 帮我们在 Executors 中准备了几个静态工厂方法,我们一起看一下它们的特性:newFixedThreadPool(int nThreads) 可以创建一个固定线程数量的线程池,同时它的工作队列是一个无界队列。newSingleThreadExecutor() 可以创建只有一个线程工作的线程池,同时它的工作队列也是无界队列。newCachedThreadPool() 可以创建一个没上限工作线程的线程池,它使用了 SynchronousQueue 只要有任务过来,如果有空闲的线程,会优先利用空闲的线程池,没有空闲线程就会新创建线程。newSingleThreadScheduledExecutor() 创建的是一个具有延迟和循环执行任务线程池,同时它内部也只有一个线程,它的工作队列是一个具有延迟功能的队列 DelayedWorkQueue。newWorkStealingPool() 这种方法是 Java 8 提供的,它实际创建的是一个 ForkJoinTool 而不是 ThreadPoolExecutor 的实例。如上即为 5 中创建线程池的工厂方法,大家根据需要选择适合自己工作的,当然也可以直接使用 ThreadPoolExecutor 来创建一个。

到此,关于“Java线程池是怎么实现的”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI