线程池在项目中怎么使用的疑惑 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
dovme
V2EX    Java

线程池在项目中怎么使用的疑惑

  •  
  •   dovme 2019-06-05 11:35:14 +08:00 7296 次点击
    这是一个创建于 2400 天前的主题,其中的信息可能已经有所发展或是发生改变。
    在网上搜索,都只会讲类似使用

    ExecutorService s = Executors.newFixedThreadPool(5);

    这种方式来创建

    我想问的是: 在一个请求需要处理很复杂的运算时,使用线程池,

    那么是直接在方法里面 new 一个出来,使用完之后关闭掉?

    还是使用单例模式创建一个全局的线程池.

    我不是很理解这个

    如果说每次请求 new 一个线程池出来的话,

    在高并发下,是不是存在很多个线程池,那么内存应该会溢出的啊.

    但如果只创建一个线程池,

    在高并发下,无数的请求都排队使用那几个固定的线程,不是更慢了吗?

    ava 里面每个 web 请求过来都是一个线程,不使用线程池的话,

    自己的线程处理自己的事情,比所有请求共用一个线程池快得多吧.

    我不知道我这么想对不对.但是我使用 apache 的 ab 同时请求 1000 次的话,

    不使用线程池比使用单例的线程池快很多很多.

    希望大佬来帮小弟解惑.
    20 条回复    2019-06-05 17:31:08 +08:00
    gosansam
        1
    gosansam  
       2019-06-05 11:48:51 +08:00   1
    #### 首先用 Spring 创建一个线程池的 Bean 例如 taskExecutor,需要异步处理的方法上添加 @Async("taskExecutor"),这样调用异步方法就会使用这个线程池。
    #### 线程池这个东西肯定不是需要就 new 一个,为什么使用线程池? 为了节省线程创建和销毁带来的消耗,每次 new 一个线程池比每次 new 一个线程开销更大。
    #### 高并发下,需要根据机器配置设计合理的线程池参数,使用线程池是为了异步部分请求,加速全局请求。
    dovme
        2
    dovme  
    OP
       2019-06-05 11:59:56 +08:00
    @gosansam #1 使用 @Async 注解 方法并发执行,还需要线程池吗?还是说防止异步线程太多,才使用线程池?
    dovme
        3
    dovme  
    OP
       2019-06-05 12:03:05 +08:00
    @dovme #2 所以说我理解错了,线程池一般都是异步执行,而不是同步对吗?
    pursuer
        4
    pursuer  
       2019-06-05 12:11:21 +08:00 via Android   1
    怕线程不够就不要创建固定线程池,用动态增长的线程池(好像叫 CachedThreadPool?)不就可以了
    cxtrinityy
        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 个线程在并发
    dovme
        6
    dovme  
    OP
       2019-06-05 12:40:47 +08:00
    @cxtrinityy #5 使用 newCache 这个创建的线程池,如果 1000 个请求过来,会创建 000 个线程?目前 4 vCPU 8 GiB 内存这样的服务器,能承受多少线程而不出什么问题呢?
    chendy
        7
    chendy  
       2019-06-05 12:58:34 +08:00   1
    snappyone
        8
    snappyone  
       2019-06-05 13:19:06 +08:00   1
    @dovme 最佳线程数取决于你要处理的任务类型和你的 cpu 数量,简单的说 cpu 密集型任务就跟 cpu 数量差不多的线程数就可以了,而 io 密集型则线程可以设置比较大(具体多大需要测试才知道),线程创建太多会导致 cpu 上下文切换造成额外无必要的性能开销
    Beeethoven
        9
    Beeethoven  
       2019-06-05 13:39:00 +08:00   1
    我理解线程池并不是一个解决高并发的好方法。一般我都是在后台处理复杂数据时用的,接收到请求时,主线程处理简单的部分并返回结果,复杂的部分开个新线程扔过去慢慢处理。
    cxtrinityy
        10
    cxtrinityy  
       2019-06-05 13:40:14 +08:00 via Android   1
    @dovme 不一定会有 1000 个,因为如果某个线程执行完任务就会被复用
    至于内存方面,没有具体计算过,不过一个具体线程并不会占用太多内存,具体到 runnable 看实现,这些都可以通过类内定义的变量来计算的,不过 1000 个对象应该没什么压力
    至于 CPU,楼上说的挺清楚了
    f2ed
        11
    f2ed  
       2019-06-05 13:44:35 +08:00   1
    当然是创建 CPU 核心数量的线程数了
    Takamine
        12
    Takamine  
       2019-06-05 13:51:53 +08:00 via Android   1
    线程池是为了节省频繁创建的开销,另外一方面是对系统资源稳定的一种保护。
    一般线程数取计算密集型 N+1,IO 密集型 2N,然后再调整,可以查一下公式。
    简单计算就是 线程数= cpu 数 /( 1-阻塞率)。
    axbx
        13
    axbx  
       2019-06-05 14:07:55 +08:00   1
    一般用线程池是为了避免异步处理任务的时候重复创建线程的开销,使用 TheadPoolTaskExectour 来创建线程池 Bean,整个项目都用这个 Bean 创建线程。
    0xZhangKe
        14
    0xZhangKe  
       2019-06-05 14:10:12 +08:00   1
    首先线程池是用来解决线程共用问题的,此外不同的线程池解决的问题多少有些不同。
    面对这样的设定,我们可以设想一下不同的线程池可以解决什么样的问题。
    例如我们可以创建一个线程数固定为 1 的全局单利线程池,用来执行一些优先级实时性都不高,但可能个数较多的任务。比如定期收集日志并上传、获取设备内存等状态信息、检测并清理运行时的垃圾文件等等。
    同样,可以创建一个固定个数为 CPU 核心数的全局单利线程池,用来执行一些实时性要求较高,但也没这么高的任务,例如网络请求,网络请求框架 Volley 使用的就是个数为 4 的全局单利线程数组来执行网络请求。
    ligz
        15
    ligz  
       2019-06-05 14:24:36 +08:00   1
    谈谈我的理解。首先一般不使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方更加明确线程池的运行规则,规避资源耗尽的风险。

    其次,肯定不是需要的时候就 new 一个出来,而是通过全局配置的线程池,有这么个作用
    1. 降低资源消耗。 通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
    2. 提高响应速度。 当任务到达时,任务可以不需要的等到线程创建就能立即执行。

    你需要设定核心线程数和最大线程数,一般根据你 cpu 的核数和是 IO 型的任务还是 CPU 型的任务决定,不会无限制的创建线程的,多余的任务存储在你设置的队列里面,比如阻塞队列 BlockingQueue。

    真正执行计算逻辑的还是你操作系统的线程,当你的任务操作时间很短或者数量很少的时候,看不出什么区别,甚至会更慢。如果你没提前创建好线程池,线程池的创建时间可能比你执行那些请求的时间都长。
    shangfabao
        16
    shangfabao  
       2019-06-05 14:25:05 +08:00   1
    看你自己的使用场景了,大部分是固定几个线程池
    qiyuey
        17
    qiyuey  
       2019-06-05 14:29:52 +08:00   1
    线程池的问题在于你需要估计线程池的配置,注意是估计,应为线程池的配置其实是没办法准确计算的,需要通过压测来不断调整。即使配置相对合理之后,仍不能避免线程阻塞导致的线程切换的成本。不如直接用 Coroutines 和 Reactive。
    dovme
        18
    dovme  
    OP
       2019-06-05 14:41:57 +08:00
    @ligz #15
    @0xZhangKe #14
    @cxtrinityy #10
    @qiyuey #17
    @axbx #13
    @gosansam #1 谢谢大佬们详细的解答.非常感谢
    securityCoding
        19
    securityCoding  
       2019-06-05 15:06:56 +08:00   1
    spring 中的 taskExecutor bean 就是单例的,跟你自己创建差不多
    quickma
        20
    quickma  
       2019-06-05 17:31:08 +08:00
    Java 并发实战推荐给你
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1227 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 24ms UTC 17:29 PVG 01:29 LAX 09:29 JFK 12:29
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86