复用的艺术:线程池

Posted 给产品经理讲技术

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了复用的艺术:线程池相关的知识,希望对你有一定的参考价值。

在开始之前,建议你先大体翻一下这些关于线程的文章。




学习编程必然绕不开多线程。实现一个功能,你既可以选择串行的方式,一条路走到天黑,也可以选择多线程,多条腿一起走。现在的CPU动辄四核八核的,如果自始至终只让一个核干活,那跟薅羊毛只薅一只羊有什么区别?

但是很快你就会了解到,线程这东西,也不是你想用、想用就能随便用的。

前几天的文章《》和大家一起动手搭了一个服务器(其实就是装了一个叫nginx的软件)。虽然简单,但是不影响我们学习服务器的原理:服务器就是用来接收并响应客户端的网络请求的。最简单的工作流程是,每次收到一个请求,就开一个线程去处理,这样可以最大化的利用CPU的并行处理能力。

但是,假如你同时接收10w个请求,也要开10w个线程吗?肯定是不可以的,原因有三:

  1. 操作系统都有线程分配的最大值,比如linux系统一般只允许分配1024个。第一关你首先过不了。

  2. 操作系统创建线程的时候需要同时分配一些内存,虽然服务器的内存都很大,但也不是用不完的,地主家也没有余粮,不是吗?

  3. CPU创建一个线程和销毁一个线程是要花时间的,甭管多快,肯定比直接拿来用要慢吧。

如果不好理解,可以举个例子。

有一天你招了一帮码农帮你做需求。平时有需求的时候,大家很开心,一人分配一个,多线程并行工作,很快就交付了。没需求的时候呢,你嫌他们白拿工资,就全都fire掉了。这其实是不明智的。先不说你随便fire别人要付N+1,依现在的行情,招一个靠谱点儿的码农想必也是一个「众里寻他千百度」的事情吧。权衡一二,我还是建议你搞一个池子,把他们圈养起来,下次有需求了直接取,用完扔回池子里,只需要咬咬牙给他们发工资就行了。

线程池也是一样的道理。既然服务器不可能无上限的分配线程,那就弄个盛放线程的池子,先分配几个在里面放着,用到的时候直接取,用完再扔回去,循环往复,子子孙孙无穷尽也,岂不快哉?

原理就是这样的,那用什么来实现呢?

给你5秒钟想一下,想不出来的自觉打赏哈。

我们把问题抽象一下,现在有很多「请求」不断的涌入到你的服务器,同时你的服务器创建了一个线程池,里面有一堆可以「处理」请求的线程。这是什么?这是「生产者消费者模型」啊,想起来了没,讲过的哦。

在这个模型里,「生产者」就是一个个客户端,生产的是「网络请求」,「消费者」就是线程池里的线程,消费的也是「网络请求」,消费的过程就是响应网络请求的过程。当然,有时候网络请求太多,线程池里没有足够空闲的线程的时候,就会把请求放到一个队列里去排队。

所以你们双11的时候抢不到促销商品,可以理解为淘宝的服务器线程池里的线程用完了,你的请求被放到队列里去,等别人买完了让出线程才能轮到你。

这就是线程池的缺点,它可能会导致请求得不到及时的处理。但是这总比你一下在分配太多的线程直接把服务器搞挂掉要强吧?

程序员的世界里,像线程池这样的还有很多,比如对象池、连接池、指令池、炮友池等等。把一个东西「池化」是一种很典型的复用思想,它的核心就是,这些东西如果可以重复使用的话,就尽量不要销毁它。

以上是关于复用的艺术:线程池的主要内容,如果未能解决你的问题,请参考以下文章

多线程之线程池ThreadPoolExecutor

Java多线程系列-- Fork&Join框架,分治的艺术

android线程与线程池-----线程池《android开发艺术与探索》

java并发的艺术-读书笔记-第九章线程池

线程复用:线程池

线程池 -实现线程复用