1
gosansam 2019-06-05 11:48:51 +08:00 1
#### 首先用 Spring 创建一个线程池的 Bean 例如 taskExecutor,需要异步处理的方法上添加 @Async("taskExecutor"),这样调用异步方法就会使用这个线程池。
#### 线程池这个东西肯定不是需要就 new 一个,为什么使用线程池? 为了节省线程创建和销毁带来的消耗,每次 new 一个线程池比每次 new 一个线程开销更大。 #### 高并发下,需要根据机器配置设计合理的线程池参数,使用线程池是为了异步部分请求,加速全局请求。 |
4
pursuer 2019-06-05 12:11:21 +08:00 via Android 1
怕线程不够就不要创建固定线程池,用动态增长的线程池(好像叫 CachedThreadPool?)不就可以了
|
5
cxtrinityy 2019-06-05 12:18:57 +08:00 1
线程池也有很多种的,1L 也说了,主要是为了节省创建线程的开销,复用已创建线程,用的时候一般都是全局 new 1 个或者你有特殊需求 new N 个
比如你举的例子,是固定线程数量为 5 的线程池,不管几个 runnable,callable 过来,同时跑的线程只有 5 个,其他的都得排队,还有 newCache (按需创建,默认线程数量上限整形上届,不保存固定数量线程,idle 线程存活 60 秒)、newSingle (单线程复用)等等,可以看看 至于你说的 1000 个请求不使用线程池比较快,得具体情况具体分析,如果你用的是像你举的例子那样,那肯定是按需 new 线程快,毕竟线程池里只有 5 个线程在并发 |
6
dovme OP @cxtrinityy #5 使用 newCache 这个创建的线程池,如果 1000 个请求过来,会创建 1000 个线程?目前 4 vCPU 8 GiB 内存这样的服务器,能承受多少线程而不出什么问题呢?
|
7
chendy 2019-06-05 12:58:34 +08:00 1
|
8
snappyone 2019-06-05 13:19:06 +08:00 1
@dovme 最佳线程数取决于你要处理的任务类型和你的 cpu 数量,简单的说 cpu 密集型任务就跟 cpu 数量差不多的线程数就可以了,而 io 密集型则线程可以设置比较大(具体多大需要测试才知道),线程创建太多会导致 cpu 上下文切换造成额外无必要的性能开销
|
9
Beeethoven 2019-06-05 13:39:00 +08:00 1
我理解线程池并不是一个解决高并发的好方法。一般我都是在后台处理复杂数据时用的,接收到请求时,主线程处理简单的部分并返回结果,复杂的部分开个新线程扔过去慢慢处理。
|
10
cxtrinityy 2019-06-05 13:40:14 +08:00 via Android 1
@dovme 不一定会有 1000 个,因为如果某个线程执行完任务就会被复用
至于内存方面,没有具体计算过,不过一个具体线程并不会占用太多内存,具体到 runnable 看实现,这些都可以通过类内定义的变量来计算的,不过 1000 个对象应该没什么压力 至于 CPU,楼上说的挺清楚了 |
11
f2ed 2019-06-05 13:44:35 +08:00 1
当然是创建 CPU 核心数量的线程数了
|
12
Takamine 2019-06-05 13:51:53 +08:00 via Android 1
线程池是为了节省频繁创建的开销,另外一方面是对系统资源稳定的一种保护。
一般线程数取计算密集型 N+1,IO 密集型 2N,然后再调整,可以查一下公式。 简单计算就是 线程数= cpu 数 /( 1-阻塞率)。 |
13
axbx 2019-06-05 14:07:55 +08:00 1
一般用线程池是为了避免异步处理任务的时候重复创建线程的开销,使用 TheadPoolTaskExectour 来创建线程池 Bean,整个项目都用这个 Bean 创建线程。
|
14
0xZhangKe 2019-06-05 14:10:12 +08:00 1
首先线程池是用来解决线程共用问题的,此外不同的线程池解决的问题多少有些不同。
面对这样的设定,我们可以设想一下不同的线程池可以解决什么样的问题。 例如我们可以创建一个线程数固定为 1 的全局单利线程池,用来执行一些优先级实时性都不高,但可能个数较多的任务。比如定期收集日志并上传、获取设备内存等状态信息、检测并清理运行时的垃圾文件等等。 同样,可以创建一个固定个数为 CPU 核心数的全局单利线程池,用来执行一些实时性要求较高,但也没这么高的任务,例如网络请求,网络请求框架 Volley 使用的就是个数为 4 的全局单利线程数组来执行网络请求。 |
15
ligz 2019-06-05 14:24:36 +08:00 1
谈谈我的理解。首先一般不使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方更加明确线程池的运行规则,规避资源耗尽的风险。
其次,肯定不是需要的时候就 new 一个出来,而是通过全局配置的线程池,有这么个作用 1. 降低资源消耗。 通过重复利用已创建的线程降低线程创建和销毁造成的消耗。 2. 提高响应速度。 当任务到达时,任务可以不需要的等到线程创建就能立即执行。 你需要设定核心线程数和最大线程数,一般根据你 cpu 的核数和是 IO 型的任务还是 CPU 型的任务决定,不会无限制的创建线程的,多余的任务存储在你设置的队列里面,比如阻塞队列 BlockingQueue。 真正执行计算逻辑的还是你操作系统的线程,当你的任务操作时间很短或者数量很少的时候,看不出什么区别,甚至会更慢。如果你没提前创建好线程池,线程池的创建时间可能比你执行那些请求的时间都长。 |
16
shangfabao 2019-06-05 14:25:05 +08:00 1
看你自己的使用场景了,大部分是固定几个线程池
|
17
qiyuey 2019-06-05 14:29:52 +08:00 1
线程池的问题在于你需要估计线程池的配置,注意是估计,应为线程池的配置其实是没办法准确计算的,需要通过压测来不断调整。即使配置相对合理之后,仍不能避免线程阻塞导致的线程切换的成本。不如直接用 Coroutines 和 Reactive。
|
18
dovme OP |
19
securityCoding 2019-06-05 15:06:56 +08:00 1
spring 中的 taskExecutor bean 就是单例的,跟你自己创建差不多
|
20
x7395759 2019-06-05 17:31:08 +08:00
Java 并发实战推荐给你
|