线程池工作原理及实现-线程池原理实现
线程池那点事儿,实际上就是给 CPU 找点乐子 想象一下,你开了一家超级大的餐馆,叫“万宝つながり”(万事相连)。每来一桌饭,服务员就得跑出去买菜、端盘子,别看看着繁华,但每一道菜都能重复做,不像你打了一架,下次还得从头练手。线程池正是干这种事的,它相当于在灶台间门口预备了五套菜童兼厨师,专门负责处理那些重复又耗时的订单。 你不用每次都喊“去灶台间吧”,只要只要那餐饭还在排队,灶台间那边的人就会自动响应。
这种机制能帮咱们省事儿,把“时刻在线”的 CPU 空闲工夫逼成“空闲等待”。 硬件层面实际上挺好办的,就像拿着一把钥匙,每把钥匙能开不同的锁。CPU 里面有一堆 CPU,这五套菜童就是那五把钥匙。你要干活,就按对应钥匙的锁,不用每次重新去拧。自然,这也得讲究个效率,要是进程忒慢,你每次都让 CPU 空转等待,那就亏了。 实际落地时,线程池的工作逻辑挺微妙。当有新任务进来,要是这任务能立马执行,那就用空闲的线程干;要是线程队里空了,就拿走一个空闲线程干完,再送回去排队。
这就好比你去帮别人洗车,对方说“我这就走”,你赶紧把车洗了,对方又让你洗,你持续忙。 线程池是个容器,比如名字叫 `shutaman`,里面装着一组线程。新任务来了,只要手里没空闲线程,那就去抢;一旦抢到,任务就扔进去,线程就去干。干完就吐出来,下次再需求时,新线程就被扔进去。 举个例子,假设你在处理图片。每算一张图都得等, صور (照片)。
第一张图用线程 A 干,干了就去排队。
要是立马又有第二张图,线程 A 可能刚忙完,第二张图还没让它去排队,那就拿个新线程 B 去干。
这时候你会发现,线程池里实际上有两行正在运行的代码,别看它们再“看起来”像是两个独立的进程,但在内存空间里,它们实际上是共享着一份状态的。 这就好比你在排队等电梯,前面的人走了,后面的人没走,你就持续等。线程池就是那个“电梯”,它保证你今天去叫电梯,明天去叫电梯,不用每次都费劲去找电梯员。 在 Java 里调用线程池,实际上挺像分派任务给服务员。你构造一个线程池对象,指定线程数量,比如 `Executors.newFixedThreadPool(10)`。
这就意味着你给了 10 个厨师。当新任务来了,要是这 10 个厨师里没人,就派去干。干完吐出来,要么放回队里,要么就直接去执行。 这里有个细节,线程池不是个牢笼,是个工作槽。线程一旦进去了,任务就扔进去,线程干完就走。任务不是塞进去就等着,线程是活的,它干完任务会吐出来。
要是任务快干完,线程还没吐出来,新的任务又来了,这线就重新被塞进去,持续干。 这也解释了为啥线程池要设个大小。
要是任务忒多,线程池的大小小了,线程干完没吐出来,新任务来了,线程只能一直排队,这时候 CPU 就得一直空转。
要是大小大了,线程干了没任务,就得一直等,这时候别看 CPU 能干活,但没多少活干,也像是在等电梯一样。 比如你有个任务,每 50 毫秒跑一次,线程池大小定得忒大,那线程可能干完就等,CPU 就空转了。线程池大小定得忒小,那任务跑了,线程就积压在队列里,新任务来了,线程一直排队,CPU 就空转了。 还有一个常见的坑,是在 `Executors.newScheduledThreadPool` 里。
要是你指定了固定线程数,但任务执行工夫不固定,那线程池大小就务必定得比任务多,不然线程数不够,任务就得一直排队。 `ScheduledThreadPool` 是个定时任务池,它和一般/平平的线程池不一样,它不像是拿钥匙开锁,它更像是一个排队系统。
要是线程池满了,任务就得进队列,队列满了还得进等待队列。 再说说数据量。假设你要处理 100 个图片,每个图片需求 100 毫秒。线程池大小定得不够,线程干完没吐出来,新的任务又来了,线程就排队,这时候 CPU 就空转了。
要是线程池大小定得忒大,线程干完没任务,线程就等,CPU 也空转了。 故此线程池大小定得刚刚好。任务来了,线程干完吐出来;任务没来,线程就排队。
这样 CPU 就不会一直空转,也不会一直等。 最终总结一下,线程池就是个“复用器”。它把 CPU 闲置工夫逼出来,让任务有地儿散。它不锁任务,任务走哪儿跟哪儿,线程干完吐出来,任务再走。
只要弄对大小和类型,这就算是个不错的工具。
声明:演示网站所有内容,若无特殊说明或标注,均来源于网络转载,仅供学习交流使用,禁止商用。若本站侵犯了你的权益,可联系本站删除。
