boy-learning-thread | 1.1.6 线程池原理

相关源码:boy-learning-thread
个人博客:http://bruce.bugmakers.club
内容来自《网易微专业 - 高性能编程章节》

线程池原理

1、为什么要用线程池

线程是不是越多越好?

1、线程在 java 中是一个对象,更是操作系统中的资源,线程创建、销毁需要时间。如果 “创建时间 + 销毁时间 > 执行任务时间” 就恨不合算。

2、java 对象占用堆内存,操作系统线程占用系统内存,根据 jvm 规范,一个线程默认最大栈大小 1M,这个空间是需要从系统内存中分配的。线程过多,会消耗很多内存。

3、操作系统需要频繁切换线程上下文(大家都想被执行),线程过多会影响性能。

线程池的推出,就是为了方便的控制线程数量。

2、线程池原理 - 概念

1、线程池管理器:用于创建并管理线程池,包括:创建线程池、销毁线程池、添加新任务;

2、工作线程:线程池中的线程,在没有任务时处于等待状态,可以循环的执行任务;

3、任务接口:每个任务必须实现的接口,以供工作线程调度任务的执行,它主要规定了:任务的入口、任务执行完后的收尾工作、任务的状态;

4、任务队列:用于存放没有处理的任务。以供一种缓冲机制。

2.1、线程池 API - 接口定义和实现类

类型 名称 描述
接口 Executor 最上层接口,定义了执行任务的方法 execute
接口 ExecutorService 继承了 Executor 接口,拓展了 Callable、Future、关闭方法
接口 ScheduledExecutorService 继承了 ExecutorService,增加了定时任务相关的方法
实现类 ThreadPoolExecutor 基础、标准的线程池实现类
实现类 ScheduledThreadPoolExecutor 继承了 ThreadPoolExecutor,实现了 ScheduledExecutorService 中相关定时任务的方法

可以认为 ScheduledThreadPoolExecutor 是最丰富的实现类。

2.2、线程池 API - 方法定义

ExecutorService

// 监测 ExecutorService 是否已关闭,直到所有任务完成执行,或超时发生,或当前线程被中断  
awaitTermination(long timeout, TimeUnit unit);

// 执行给定的任务集合,执行完毕后,返回结果
invokeAll(Collection<? extends Callable<T>> tasks);

// 执行给定的任务集合,执行完毕或者超时后,返回结果,其他任务终止
invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit);

// 执行给定的任务集合,任意一个任务执行成功后,返回结果,其他任务终止
invokeAny(Collection<? extends Callable<T>> tasks);

// 执行给定的任务集合,任意一个任务执行成功或超时后,返回结果,其他任务终止
invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit);

// 如果线程池关闭,则返回treu
isShutdown();

// 如果关闭后,所有任务都已经执行完毕,则返回true
isTerminated();

// 优雅关闭线程池,之前已经提交的任务将被执行,但不接受新的任务
shutdown();

// 尝试停止所有正在执行的任务,停止等待任务的处理,并返回等待执行任务的列表
shutdownNow();

// 提交一个用于执行的 Callable 返回任务,并返回一个 Future 对象,用于获取 Callable 执行结果
submit(Callable<T> task);

// 提交可运行任务以执行,并返回一个 Future 对象,执行结果为 null
submit(Runnable task);

// 提交可运行任务以执行,并返回一个 Future 对象,执行结果为传入的 result
sumit(Runnable task, T result);

ScheduledExecutorService

// 创建并执行一个一次性任务,过了延迟时间就会被执行
schedule(Callable<T> callable, long delay, TimeUnit unit);
schedule(Runnable command, long delay, TimeUnit unit);

// 创建并执行一个周期性任务,过了延迟时间会第一次执行,执行过程发生异常,那么任务就停止了
scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit);
scheduleWithFixedDelay(Runnable command, long initialDelay, long period, TimeUnit unit);

scheduleAtFixedRate 方法,一次任务执行时长超过周期时间,下次任务在该次任务执行完之后,立即执行。
schedualWithFixedDelay 方法,一次任务执行时间长超过周期时间,下次任务会在该次任务执行完之后,计算执行延时(再等延迟一个 period 的时长)。

2.3、线程池 API - Executors 工具类

你也可以自己实例化线程池,也可以用 Executors 创建线程池的工厂类,常用方法如下:

1) newFixedThreadPool(int nThreads)

创建一个固定大小、任务队列无界的线程池。核心线程数 = 最大线程数。

2) newCachedThreadPool()

创建一个大小无界的缓存线程池。他的任务队列是一个同步队列。
任务加入到池中,如果池中有空闲线程,则用空闲线程执行,如无则创建新的线程执行,池中的线程空闲超过60秒,将被销毁释放。
线程数随任务的多少变化。适用于任务量不可控,且执行耗时较小的异步任务。
核心线程数 = 0, 最大线程数 = Integer.MAX_VALUE

3) newSingleThreadExecutor()

只有一个线程来执行无界任务队列的单一线程池。该线程池确保任务按照加入队列的顺序一个一个一次执行。
当唯一的线程因任务异常终止时,将创建一个新的线程来执行后续的任务。
与 newFixedThreadPool(1) 的区别在于,单一线程池的大小在 new SingleThreadExecutor 方法中硬编码,不能再改变。

4) newScheduledThreadPool(int corePoolSize)

能定时执行任务的线程池。该池的核心线程数由参数来指定,最大线程数 = Integer.MAX_VALUE

3、线程池原理 - 任务 execute 过程

1、是否达到核心线程数量?没达到,创建一个工作线程来执行任务。

2、任务队列是否已满?没满,则将新提交的任务存储在任务队列里边。

3、是否达到线程池最大数量?没达到,则创建一个新的工作线程来执行任务。

4、最后,执行拒绝策略来处理这个任务。

4、线程数量

如何确定合适数量的线程?

计算型任务:cpu数量的1~2倍。

IO型任务:根据具体的IO阻塞时长进行考量决定。

如 Tomcat 中默认的最大线程数为:200

也可以考虑根据需要在一个最小数量和最大数量间自动增减线程数。

监控CPU的使用率,如果远小于80%则使用不合理,大于也不可理,接近则表示使用良好。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,538评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,800评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,329评论 0 238
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,725评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,089评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,449评论 1 212
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,758评论 2 311
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,448评论 0 195
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,152评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,432评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,933评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,289评论 2 252
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,921评论 3 234
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,023评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,781评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,477评论 2 270
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,381评论 2 263

推荐阅读更多精彩内容

  • 线程池主要用来解决线程生命周期开销问题和资源不足问题。通过对多个任务重复使用线程,线程创建的开销就被分摊到了多个任...
    安仔夏天勤奋阅读 991评论 0 10
  • 线程池中有一定数量的工作线程,工作线程会循环从任务队列中获取任务,并执行这个任务。那么怎么去停止这些工作线程呢?这...
    wo883721阅读 1,561评论 0 14
  • 222
    Sean_9f73阅读 189评论 0 0
  • 真实经历:在之前的项目中,UI小姐姐告诉我们一位前端小姐姐说我们项目苹果手机中的边框好像不是1像素的,比1像素粗。...
    星飞822阅读 468评论 0 0
  • 几天前做了一个梦。 我在老房子里,在跟爷爷一起睡的那张床上,在爷爷身边。爷爷突然转过身,抱着我,一股爷爷的席卷而来...
    怎一个强字了得阅读 54评论 0 0