详谈线程池的理解和应用

2024-08-21 13:58
文章标签 线程 应用 理解 详谈

本文主要是介绍详谈线程池的理解和应用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、线程池的好处

线程池是啥子,干啥使它呀,老子线程使得好好的,非得多次一举,哈哈,想必来这里看这篇文章的都对线程池有点了解。那么我来整理整理线程池的好处吧。

1、线程池的重用

线程的创建和销毁的开销是巨大的,而通过线程池的重用大大减少了这些不必要的开销,当然既然少了这么多消费内存的开销,其线程执行速度也是突飞猛进的提升。

2、控制线程池的并发数

初学新手可能对并发这个词语比较陌生,特此我也是结合百度百科和必生所学得出最优解释,万万记着并发可跟并行不一样。

并发:在某个时间段内,多个程序都处在执行和执行完毕之间;但在一个时间点上只有一个程序在运行。头脑风暴:老鹰妈妈喂小雏鹰食物,小雏鹰很多,而老鹰只有一张嘴,她需要一个个喂过去,到最后每个小雏鹰都可以吃到,但是在一个时间点里只能有一个小雏鹰可以吃到美味的食物。

并行:在某个时间段里,每个程序按照自己独立异步的速度执行,程序之间互不干扰。头脑风暴:这就好似老鹰妈妈决定这样喂食太费劲于是为每个小雏鹰请了个保姆,这样子在一个时间点里,每个小雏鹰都可以同时吃到食物,而且互相不干扰。

回到线程池,控制线程池的并发数可以有效的避免大量的线程池争夺CPU资源而造成堵塞。头脑风暴:还是拿老鹰的例子来讲,妈妈只有一个,要这么一个个喂下去,一些饿坏的小雏鹰等不下去了就要破坏规则,抢在靠前喂食的雏鹰面前,而前面的雏鹰也不是吃软饭的,于是打起来了,场面混乱。老鹰生气了,这么不懂事,谁也别吃了,于是造成了最后谁也没食吃的局面。

3、线程池可以对线程进行管理

线程池可以提供定时、定期、单线程、并发数控制等功能。比如通过ScheduledThreadPool线程池来执行S秒后,每隔N秒执行一次的任务。

二、线程池的详解

推荐博客: http://blog.csdn.net/seu_calvin/article/details/52415337

想必看完上面那篇博客,大家可谓赞不绝口,不过可能有些小伙伴还是记不下来,还有些小伙伴觉得好恶心呀,怎么都是厕所啥的呀!哈哈别着急,我来给大家一种好记的办法。

先来讲讲参数最多的那个构造方法,主要是对那几个烦人的参数进行分析。

1、ThreadPoolExecutor

public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler) {...
}

这里是7个参数(我们在开发中用的更多的是5个参数的构造方法),OK,那我们来看看这里七个参数的含义:

  • corePoolSize 线程池中核心线程的数量
  • maximumPoolSize 线程池中最大线程数量
  • keepAliveTime 非核心线程的超时时长,当系统中非核心线程闲置时间超过keepAliveTime之后,则会被回收。如果ThreadPoolExecutor的allowCoreThreadTimeOut属性设置为true,则该参数也表示核心线程的超时时长
  • unit 第三个参数的单位,有纳秒、微秒、毫秒、秒、分、时、天等
  • workQueue 线程池中的任务队列,该队列主要用来存储已经被提交但是尚未执行的任务。存储在这里的任务是由ThreadPoolExecutor的execute方法提交来的。
  • threadFactory 为线程池提供创建新线程的功能,这个我们一般使用默认即可
  • handler 拒绝策略,当线程无法执行新任务时(一般是由于线程池中的线程数量已经达到最大数或者线程池关闭导致的),默认情况下,当线程池无法处理新线程时,会抛出一个RejectedExecutionException。

emmmmm…看到那么多烦人的概念,是不是有点头大了,我反正是头大了。

这7个参数中,平常最多用到的是corePoolSize、maximumPoolSize、keepAliveTime、unit、workQueue.在这里我主要抽出corePoolSize、maximumPoolSize和workQueue三个参数进行详解。

maximumPoolSize(最大线程数) = corePoolSize(核心线程数) + noCorePoolSize(非核心线程数)

(1)当currentSize<corePoolSize时,没什么好说的,直接启动一个核心线程并执行任务。

(2)当currentSize>=corePoolSize、并且workQueue未满时,添加进来的任务会被安排到workQueue中等待执行。

(3)当workQueue已满,但是currentSize<maximumPoolSize时,会立即开启一个非核心线程来执行任务。

(4)当currentSize>=corePoolSize、workQueue已满、并且currentSize>maximumPoolSize时,调用handler默认抛出RejectExecutionExpection异常。

什么currentSize,corePoolSize,maximumPoolSize,workQueue比来比去的都比迷糊了,哈哈,那我举个烧烤店的例子来想必大家理解起来更快。

夏天了,很热,所以很多烧烤店都会在外面也布置座位,分为室内、室外两个地方可以吃烧烤。(室内有空调电视,而且室内比室外烧烤更加优惠,而且外面下着瓢泼大雨所以顾客会首先选择室内)

corePoolSize(烧烤店室内座位),currentPoolSize(目前到烧烤店的顾客数量),maximumPoolSize(烧烤店室内+室外+侯厅室所有座位),workQueue(烧烤店为顾客专门设置的侯厅室)

第(1)种,烧烤店人数不多的时候,室内位置很多,大家都其乐融融,开心的坐在室内吃着烧烤,看着世界杯。

第(2)种,生意不错,室内烧烤店坐无空席,大家都不愿意去外面吃,于是在侯厅室里呆着,侯厅室位置没坐满。

第(3)种,生意兴隆,室内、侯厅室都坐无空席,但是顾客太饿了,剩下的人没办法只好淋着雨吃烧烤,哈哈,好可怜。

第(4)种,生意爆棚,室内、室外、侯厅室都坐无空席,再有顾客过来直接赶走。

对于workQueue还是有点陌生的小伙伴。

推荐博客: http://blog.csdn.net/u0127025...

2、其他线程池的记法

在这里主要是跟大家分享一种特别容易记住其他四种线程池的方法,在大家写代码,面试时可以及时想到这四种线程池。

(1)FixedThreadPool:

Fixed中文解释为固定。结合在一起解释固定的线程池,说的更全面点就是,有固定数量线程的线程池。其corePoolSize=maximumPoolSize,且keepAliveTime为0,适合线程稳定的场所。

(2)SingleThreadPool:

Single中文解释为单一。结合在一起解释单一的线程池,说的更全面点就是,有固定数量线程的线程池,且数量为一,从数学的角度来看SingleThreadPool应该属于FixedThreadPool的子集。其corePoolSize=maximumPoolSize=1,且keepAliveTime为0,适合线程同步操作的场所。

(3)CachedThreadPool:

Cached中文解释为储存。结合在一起解释储存的线程池,说的更通俗易懂,既然要储存,其容量肯定是很大,所以他的corePoolSize=0,maximumPoolSize=Integer.MAX_VALUE(2^32-1一个很大的数字)

(4)ScheduledThreadPool:

Scheduled中文解释为计划。结合在一起解释计划的线程池,顾名思义既然涉及到计划,必然会涉及到时间。所以ScheduledThreadPool是一个具有定时定期执行任务功能的线程池。

三、线程池的单例

什么是单例呢?咳咳。

1、单例

单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

注意事项:

  • 单例类只能有一个实例。
  • 单例类必须自己创建自己的唯一实例。
  • 单例类必须给所有其他对象提供这一实例。
推荐: http://www.runoob.com/design-...

2、线程池的单例

那么问题来了,我线程池用的好好的,用的时候创建一个,不用就不管他,那为什么要将线程池设计成单例模式呢。那么就要看看你将线程池应用的场所了。一般情况下,整个系统中只需要单种线程池,多个线程公用一个线程池,不会是每创一个线程就要创建一个线程池,那样子你还不如不用线程池呢。

言归正传,咱们来看看如何将线程池设计成单例模式。废话少说上代码

首先在ThreadPool类里面实现线程池的创建,我们这里创建的是FixedThreadPool线程池(记住构造方法要私有,保证不被其他类实例化)

private ThreadPool(int corepoolsize, int maximumpoolsize, long keepalivetime) {this.corepoolsize = corepoolsize;this.maximumpoolsize = maximumpoolsize;this.keepalivetime = keepalivetime;
}public void executor(Runnable runnable) {if (runnable == null) {return;}if (mexecutor == null) {mexecutor = new ThreadPoolExecutor(corepoolsize, //核心线程数maximumpoolsize, //最大线程数keepalivetime, //闲置线程存活时间TimeUnit.MILLISECONDS, // 时间单位new LinkedBlockingDeque<Runnable>(), //线程队列Executors.defaultThreadFactory(), //线程工厂new ThreadPoolExecutor.AbortPolicy() //队列已满,而且当前线程数已经超过最大线程数时的异常处理策略);}mexecutor.execute(runnable);
}

再然后对ThreadPool内部类,在类里面对他实例化,实现单例

// 获取单例的线程池对象
public static ThreadPool getThreadPool() {if (mThreadPool == null) {synchronized (ThreadManager.class) {if (mThreadPool == null) {int cpuNum = Runtime.getRuntime().availableProcessors();// 获取处理器数量int threadNum = cpuNum * 2 + 1;// 根据cpu数量,计算出合理的线程并发数mThreadPool = new ThreadPool(threadNum, threadNum, 0L);}}}return mThreadPool;
}

这篇关于详谈线程池的理解和应用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1093356

相关文章

JDK21对虚拟线程的几种用法实践指南

《JDK21对虚拟线程的几种用法实践指南》虚拟线程是Java中的一种轻量级线程,由JVM管理,特别适合于I/O密集型任务,:本文主要介绍JDK21对虚拟线程的几种用法,文中通过代码介绍的非常详细,... 目录一、参考官方文档二、什么是虚拟线程三、几种用法1、Thread.ofVirtual().start(

Java 虚拟线程的创建与使用深度解析

《Java虚拟线程的创建与使用深度解析》虚拟线程是Java19中以预览特性形式引入,Java21起正式发布的轻量级线程,本文给大家介绍Java虚拟线程的创建与使用,感兴趣的朋友一起看看吧... 目录一、虚拟线程简介1.1 什么是虚拟线程?1.2 为什么需要虚拟线程?二、虚拟线程与平台线程对比代码对比示例:三

深入理解Mysql OnlineDDL的算法

《深入理解MysqlOnlineDDL的算法》本文主要介绍了讲解MysqlOnlineDDL的算法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小... 目录一、Online DDL 是什么?二、Online DDL 的三种主要算法2.1COPY(复制法)

Java 线程池+分布式实现代码

《Java线程池+分布式实现代码》在Java开发中,池通过预先创建并管理一定数量的资源,避免频繁创建和销毁资源带来的性能开销,从而提高系统效率,:本文主要介绍Java线程池+分布式实现代码,需要... 目录1. 线程池1.1 自定义线程池实现1.1.1 线程池核心1.1.2 代码示例1.2 总结流程2. J

利用Python操作Word文档页码的实际应用

《利用Python操作Word文档页码的实际应用》在撰写长篇文档时,经常需要将文档分成多个节,每个节都需要单独的页码,下面:本文主要介绍利用Python操作Word文档页码的相关资料,文中通过代码... 目录需求:文档详情:要求:该程序的功能是:总结需求:一次性处理24个文档的页码。文档详情:1、每个

Java JUC并发集合详解之线程安全容器完全攻略

《JavaJUC并发集合详解之线程安全容器完全攻略》Java通过java.util.concurrent(JUC)包提供了一整套线程安全的并发容器,它们不仅是简单的同步包装,更是基于精妙并发算法构建... 目录一、为什么需要JUC并发集合?二、核心并发集合分类与详解三、选型指南:如何选择合适的并发容器?在多

Java中的分布式系统开发基于 Zookeeper 与 Dubbo 的应用案例解析

《Java中的分布式系统开发基于Zookeeper与Dubbo的应用案例解析》本文将通过实际案例,带你走进基于Zookeeper与Dubbo的分布式系统开发,本文通过实例代码给大家介绍的非常详... 目录Java 中的分布式系统开发基于 Zookeeper 与 Dubbo 的应用案例一、分布式系统中的挑战二

Java 缓存框架 Caffeine 应用场景解析

《Java缓存框架Caffeine应用场景解析》文章介绍Caffeine作为高性能Java本地缓存框架,基于W-TinyLFU算法,支持异步加载、灵活过期策略、内存安全机制及统计监控,重点解析其... 目录一、Caffeine 简介1. 框架概述1.1 Caffeine的核心优势二、Caffeine 基础2

使用Node.js和PostgreSQL构建数据库应用

《使用Node.js和PostgreSQL构建数据库应用》PostgreSQL是一个功能强大的开源关系型数据库,而Node.js是构建高效网络应用的理想平台,结合这两个技术,我们可以创建出色的数据驱动... 目录初始化项目与安装依赖建立数据库连接执行CRUD操作查询数据插入数据更新数据删除数据完整示例与最佳

PHP应用中处理限流和API节流的最佳实践

《PHP应用中处理限流和API节流的最佳实践》限流和API节流对于确保Web应用程序的可靠性、安全性和可扩展性至关重要,本文将详细介绍PHP应用中处理限流和API节流的最佳实践,下面就来和小编一起学习... 目录限流的重要性在 php 中实施限流的最佳实践使用集中式存储进行状态管理(如 Redis)采用滑动