JDK1.8 创建线程池有哪几种方式?

说实话,当年我刚开始捣鼓多线程的时候,面对这么多线程池选型,脑袋嗡嗡的。
不过搞懂了它们背后的设计思路,确实能帮你少走不少弯路。

拿FixedThreadPool来说,我当年在一个做大数据处理的系统里用过。
他们那个场景特别需要控制内存和CPU峰值,因为算图计算时线程一多,JVM直接飙内存。
你看啊,FixedThreadPool就像个严格的门卫,你开几个线程就几个线程,外面排队就算1 00个任务也得乖乖等。
我记得当时配置了2 0个线程的池子,结果高峰期队列直接干到5 000条任务,那个等待时间...啧啧。
不过这种场景下,线程切换成本低,确实稳。

CachedThreadPool我倒是用得最顺手。
我们有个监控系统,大量发送日志到kafka,那种短任务特别多。
你看它多智能啊,闲着就复用线程,忙不过就创建新线程,内存够就加,不够就回收。
我当时量了量,高峰期能撑到3 00个并发,线程数在1 5 0左右浮动,比FixedThreadPool那种硬抗要省心多了。
当然,最怕的就是任务执行时间特别长,比如某个慢查询日志卡住1 0秒,整个线程池都跟着拖后腿。

ScheduledThreadPool我倒是没怎么踩坑。
但记得在一个电商秒杀系统里,他们用这个来处理定时清理Redis缓存的任务。
配置了1 0个核心线程,周期性执行,效果还挺不错。
不过要注意,它执行的任务是按顺序来的,如果你搞了个耗时特别长的定时任务,后面的都会被拖慢。

SingleThreadExecutor最简单粗暴,但特别管用。
我们有个报表生成服务,必须单线程跑,因为数据依赖顺序不能乱。
你看它多好,任务A执行完才能跑任务B,绝不含糊。
当时测试发现,双线程跑反而会因为数据不一致出bug,单线程直接解决了问题。

WorkStealingPool我倒是踩了个坑。
在一个高并发的图像处理服务里试过,结果发现CPU利用率反而不高。
后来查资料才知道,它内部用的是多个队列,线程之间互相偷任务,但你的任务如果特别短,线程来回切换的开销反而比直接执行还大。
适合那种几十毫秒到几秒的任务,太短的活儿可能不如CachedThreadPool。

说白了,线程池选型就像选车,FixedThreadPool是宝马5 系,稳但油耗高;CachedThreadPool是大众朗逸,灵活但底盘差点;ScheduledThreadPool是雷克萨斯,可靠但贵;SingleThreadExecutor是自行车,慢但绝不含糊;WorkStealingPool是F1 ,性能爆表但维护成本高。
关键是得知道你自己的路要怎么走。

在创建线程时,推荐使用以下哪些方法

创建线程嘛,有几种方法。

一种是实现Runnable接口。
这个比较经典,推荐用。
把任务逻辑和线程对象分开了。
任务逻辑在Runnable的run方法里,线程对象负责跑。
这样灵活,一个类能实现多个接口,不用管单继承的限制。
像啥多线程下载,任务封装在Runnable里,每个任务跑一个线程,不互相影响,好管理,也好扩展。

另一种是Java8 +的Lambda表达式,没啥结果要的时候用。
语法简单,直接替代匿名内部类。
代码量少,看着也明白。
比如简单记录日志啥的,用Lambda创建线程快。

最后一种是实现Callable接口。
要结果的时候用这个。
Call方法能返回结果,也能抛异常。
适合要结果或者要处理异常的情况。
比如多线程算任务,每个线程算一部分,用Callable把结果带回来,主线程再汇总。

线程池创建的四种方法是什么

newCachedThreadPool:
线程无上限。

空闲6 0秒回收。

新任务无空闲线程则新建。

短时高并发任务。

HTTP请求处理。

newFixedThreadPool:
线程数固定。

超出任务进队列。

避免线程频繁创建销毁。

空闲线程不释放。

建议Runtime.getRuntime().availableProcessors()线程数。

稳定负载后台任务。

定时数据批处理。

newSingleThreadExecutor:
单线程执行。

任务按顺序执行。

线程异常自动新建替代。

严格顺序执行场景。

日志顺序写入。

newScheduledThreadPool:
支持定时周期任务。

schedule():延迟执行。

scheduleAtFixedRate():固定频率执行。

定时任务。

心跳检测。

定时数据同步。

ThreadPoolExecutor手动配置:
核心线程数。

队列类型。

避免Executors默认配置。

newFixedThreadPool无界队列风险。

shutdown()释放资源。