当前位置:首页 > 经验 >

线程池的四种实现方式(线程池创建的几种方法)

来源:原点资讯(www.yd166.com)时间:2022-11-03 05:36:42作者:YD166手机阅读>>

不经常使用线程池的童鞋,还有对几种线程的使用不甚了解的童鞋,可以读一下此文,并关注后续线程池相关文章连载。

本篇内容大纲:

  1. 线程池的由来
  2. 线程池的优点和风险
  3. 线程池的原理和实现
  4. 线程池大小的配置

线程池的四种实现方式,线程池创建的几种方法(1)


  1. 线程池的四种实现

一、线程池的由来

我们有两种常见的创建线程的方法,一种是继承Thread类,一种是实现Runnable的接口,Thread类其实也是实现了Runnable接口。但是我们创建这两种线程在运行结束后都会被虚拟机销毁,如果线程数量多的话,频繁的创建和销毁线程会大大浪费时间和效率,更重要的是浪费内存。那么有没有一种方法能让线程运行完后不立即销毁,而是让线程重复使用,继续执行其他的任务哪?

这就是线程池的由来,很好的解决线程的重复利用,避免重复开销。

二、线程池的优点

1、线程是稀缺资源,使用线程池可以减少创建和销毁线程的次数,每个工作线程都可以重复使用。

2、可以根据系统的承受能力,调整线程池中工作线程的数量,防止因为消耗过多内存导致服务器崩溃。

三、线程池的风险

虽然线程池是构建多线程应用程序的强大机制,但使用它并不是没有风险的。用线程池构建的应用程序容易遭受任何其它多线程应用程序容易遭受的所有并发风险,诸如同步错误和死锁,它还容易遭受特定于线程池的少数其它风险,诸如与池有关的死锁、资源不足和线程泄漏。

1.死锁

任何多线程应用程序都有死锁风险。当一组进程或线程中的每一个都在等待一个只有该组中另一个进程才能引起的事件时,我们就说这组进程或线程 死锁了。死锁的最简单情形是:线程 A 持有对象 X 的独占锁,并且在等待对象 Y 的锁,而线程 B 持有对象 Y 的独占锁,却在等待对象 X 的锁。除非有某种方法来打破对锁的等待(Java 锁定不支持这种方法),否则死锁的线程将永远等下去。

2.资源不足

线程池的一个优点在于:相对于其它替代调度机制(有些我们已经讨论过)而言,它们通常执行得很好。但只有恰当地调整了线程池大小时才是这样的。

线程消耗包括内存和其它系统资源在内的大量资源。

除了 Thread 对象所需的内存之外,每个线程都需要两个可能很大的执行调用堆栈。除此以外,JVM 可能会为每个 Java 线程创建一个本机线程,这些本机线程将消耗额外的系统资源。最后,虽然线程之间切换的调度开销很小,但如果有很多线程,环境切换也可能严重地影响程序的性能。

如果线程池太大,那么被那些线程消耗的资源可能严重地影响系统性能。在线程之间进行切换将会浪费时间,而且使用超出比您实际需要的线程可能会引起资源匮乏问题,因为池线程正在消耗一些资源,而这些资源可能会被其它任务更有效地利用。

3.并发错误

线程池和其它排队机制依靠使用 wait() 和 notify() 方法,这两个方法都难于使用。如果编码不正确,那么可能丢失通知,导致线程保持空闲状态,尽管队列中有工作要处理。使用这些方法时,必须格外小心;即便是专家也可能在它们上面出错。而最好使用现有的、已经知道能工作的实现,例如在 util.concurrent 包。

4.线程泄漏

各种类型的线程池中一个严重的风险是线程泄漏,当从池中除去一个线程以执行一项任务,而在任务完成后该线程却没有返回池时,会发生这种情况。发生线程泄漏的一种情形出现在任务抛出一个 RuntimeException 或一个 Error 时。

如果池类没有捕捉到它们,那么线程只会退出而线程池的大小将会永久减少一个。当这种情况发生的次数足够多时,线程池最终就为空,而且系统将停止,因为没有可用的线程来处理任务。

5.请求过载

仅仅是请求就压垮了服务器,这种情况是可能的。在这种情形下,我们可能不想将每个到来的请求都排队到我们的工作队列,因为排在队列中等待执行的任务可能会消耗太多的系统资源并引起资源缺乏。在这种情形下决定如何做取决于您自己;在某些情况下,您可以简单地抛弃请求,依靠更高级别的协议稍后重试请求,您也可以用一个指出服务器暂时很忙的响应来拒绝请求。

四、线程池的实现原理

1.线程池状态

线程池和线程一样拥有自己的状态,在ThreadPoolExecutor类中定义了一个volatile变量runState来表示线程池的状态,线程池有四种状态,分别为RUNNING、SHURDOWN、STOP、TERMINATED。

1)线程池创建后处于RUNNING状态。

2)调用shutdown后处于SHUTDOWN状态,线程池不能接受新的任务,会等待缓冲队列的任务完成。

3)调用shutdownNow后处于STOP状态,线程池不能接受新的任务,并尝试终止正在执行的任务。

4)当线程池处于SHUTDOWN或STOP状态,并且所有工作线程已经销毁,任务缓存队列已经清空或执行结束后,线程池被设置为TERMINATED状态。

线程池原理:预先启动一些线程,线程无限循环从任务队列中获取一个任务进行执行,直到线程池被关闭。如果某个线程因为执行某个任务发生异常而终止,那么重新创建一个新的线程而已,如此反复。

2.线程池的处理流程

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

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

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

五、线程池的配置大小

一般需要根据任务的类型来配置线程池大小:

如果是CPU密集型任务,就需要尽量压榨CPU,参考值可以设为 NCPU 1

如果是IO密集型任务,参考值可以设置为2*NCPU

当然,这只是一个参考值,具体的设置还需要根据实际情况进行调整,比如可以先将线程池大小设置为参考值,再观察任务运行情况和系统负载、资源利用率来进行适当调整。

六、Java线程池的四种实现

newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。

newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。

newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。

newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

以上就是线程池的详细介绍。

栏目热文

一张图看懂线程和进程(进程与线程通俗讲解)

一张图看懂线程和进程(进程与线程通俗讲解)

进程我们都知道计算机的核心是CPU,它承担了所有的计算任务;而操作系统是计算机的管理者,它负责任务的调度、资源的分配和管...

2022-11-03 05:49:08查看全文 >>

线程池的使用实例(线程池的使用场景)

线程池的使用实例(线程池的使用场景)

线程池做什么: 网络请求通常有两种形式:第一种,请求不是很频繁,而且每次连接后会保持相当一段时间来读数据或者写数据,最后...

2022-11-03 05:37:09查看全文 >>

线程池架构原理图解(线程池工作原理及方法)

线程池架构原理图解(线程池工作原理及方法)

上篇《》文章末尾,有朋友留言提到文中的场景是IO密集型操作,不是CPU密集操作,不需要使用线程池,我猜这位朋友可能想表达...

2022-11-03 05:27:26查看全文 >>

线程池的原理及底层实现(线程池的结构和原理)

线程池的原理及底层实现(线程池的结构和原理)

作者:指尖上的榴莲www.jianshu.com/p/704a6c5d337c一.概述线程池,顾名思义就是存放线程的池子...

2022-11-03 05:47:00查看全文 >>

线程池实现的四种方式(线程池的四种状态)

线程池实现的四种方式(线程池的四种状态)

线程池的创建方式有四种,分别为手动创建,动态创建和自动生成。手动创建:创建方法有两种:(1)通过new来新建一个线...

2022-11-03 05:56:05查看全文 >>

mycat和sharding优缺点(mycat的替代品)

mycat和sharding优缺点(mycat的替代品)

在我们的项目发展到一定阶段之后,随着数据量的增大,分库分表就变成了一件非常自然的事情。常见的分库分表方式有两种:客户端模...

2022-11-03 05:56:38查看全文 >>

线程池原理和实例(线程池的结构和原理)

线程池原理和实例(线程池的结构和原理)

前言线程是稀缺资源,如果被无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,合理的使用线程池对线程进行统一分配、调...

2022-11-03 06:03:39查看全文 >>

线程池工作原理图解(线程池的结构和原理)

线程池工作原理图解(线程池的结构和原理)

前言本文以程序员做需求的例子,比喻线程池的工作过程。以故事白话的方式展开,跟大家阐述线程池工作原理,以方便大家更好理解线...

2022-11-03 05:52:26查看全文 >>

线程池底层原理(线程池设计原理图解)

线程池底层原理(线程池设计原理图解)

java的线程池说白了就是建一个任务池子跟一个线程池子,当任务池子里的任务过来了就由线程池里的活跃线程去消费,等任务池子...

2022-11-03 05:58:11查看全文 >>

java线程池工作原理(mycat和sharding优缺点)

java线程池工作原理(mycat和sharding优缺点)

关注公众号领资料搜索公众号【Java耕耘者】,回复【Java】,即可获取大量优质电子书和一份Java高级架构资料、Spr...

2022-11-03 05:30:30查看全文 >>

文档排行