线程池的由来以及用法讲解

为什么需要线程池

目前大多数的网络服务器,包括 WEB 服务器、数据库服务器等都具有一个共同点,就是单位时间内必须处理数目巨大的连接请求,但是处理时间却相对较短。传统多线程方案中采用的服务器模型是 "即使创建,即使销毁" 策略。如果提交给线程的任务是执行时间较短,而且执行频率高,那么服务器将不停的处于创建线程,销毁线程的状态。

线程执行过程

T1:线程创建时间

T2:线程执行时间,包括线程的同步等时间

T3:线程销毁的时间

线程本身的开销所占的比例:

(T1+T3) / (T1+T2+T3)

当 T2 很小时,那么线程本身带来的开销将有很大影响,所以为了解决这个问题,线程池出现了

线程池采用了预创建的技术,在应用程序启动之后,将立即创建一定数量的线程(corePoolSize),放入空闲队列中。这些线程都是处于阻塞状态,不消耗 CPU,但占用较小的内存空间。当任务到来后,缓冲池选择一个空闲线程,把任务传入此线程中运行。当 corePoolSize 个线程都在处理任务后,缓冲池自动创建一定数量 (最多 maximumPoolSize - corePoolSize) 的新线程,用于处理更多的任务。在任务执行完毕后线程也不退出,而是继续保持在池中等待下一次的任务。当系统比较空闲时(线程空闲时间超过 keepAliveTime),线程池自动销毁一部分线程,回收系统资源。 基于这种预创建技术,线程池将线程创建和销毁本身所带来的开销分摊到了各个具体的任务上,执行次数越多,每个任务所分担到的线程本身开销则越小。

线程池何时使用

1、T2 小的时候(短连接)

2、将需处理的任务的数量大

线程池的好处

1、重用存在的线程,减少对象创建、消亡的开销,性能好

2、可有效控制最大并发线程数,提高系统资源利用率,同时可以避免过多资源竞争,避免阻塞

3、提供定时执行、定期执行、单线程、并发数控制等功能

线程池的合理配置

1、CPU 密集型任务,就需要尽量压榨 CPU,参考值可以设为 CPU +1

2、IO 密集型任务,IO 密集型任务,参考值可以设置为 2*N CPU

ThreadPoolExecutor

参数

corePoolSize:核心线程数量

maximumPoolSize:线程最大线程数

workQueue:阻塞队列,存储等待执行的任务,很重要,会对线程池运行过程产生重要影响

keepAliveTime:线程没有任务执行时最多保持多久时间终止

unit:keepAliveTime 的时间单位

threadFactory:线程工厂,用来创建线程

rejectHandler:当拒绝处理任务时的策略

方法

execute()

提交任务,交给线程池执行

submit()

提交任务,能够返回执行结果 execute+Future

shutdown()

关闭线程池,等待任务都执行完(将不再接受新任务,但是会把阻塞队列里的任务执行完)

shutdownNow()

关闭线程池,不等待任务执行完

getTaskCount()

线程池已执行和未执行的任务总数

getCompletedTaskCount()

已完成的任务总数

getPoolSize()

线程池当前的线程数量

getActiveCount()

当前线程池中正在执行任务的线程数量

Executor 框架接口图

下面是一张从百度上找的接口图,是描述线程池相关接口的。

感触

在我们平时的学习中,张嘴闭嘴就是框架,我就要使用牛逼的框架,那我就是技术大牛。殊不知每个框架的出现都有一定的背景,它是用来解决某个痛点而出现的。我们沉迷在使用他们的 API 中,却很少花时间去研究 为什么用? 何时用?就像线程池一样,你不去研究它的由来,他的优点,就觉得它很牛逼,以后不管什么情况都用线程池,那你这种思想就是错误的。因为在某些情况下,它的效率和性能都不如 "即时创建,即时销毁" 。所以我们学技术是为什么解决某种场景,而不是为了学 API,API 谁几天都能用的好,但是实际的使用场景并不是每个人几天就能掌握的。

参考博文链接

https://blog.csdn.net/gukesdo/article/details/7398941

现在的喜欢,其实不是真正的喜欢,只是因为不了解而已,真正的喜欢,是建立在非常了解的基础之上的。

了解 java 基础,喜欢上编程,不再迷茫。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20181003G1AL2I00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券