SpringBoot 线程池的使用

SpringBoot 使用线程池

/**
 *  线程池的配置和初始化
 */
@Data
@ConfigurationProperties("executor")
@Configuration
public class ThreadExecutorPool {
    private Integer corePoolSize;
    private Integer maxPoolSize;
    private Integer queueCapacity;
    private Integer keepAliveSeconds;
    private String threadNamePrefix;

    @Bean("taskAsyncPool")
    public ThreadPoolTaskExecutor taskAsyncPool() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(corePoolSize);
        executor.setMaxPoolSize(maxPoolSize);
        executor.setQueueCapacity(queueCapacity);executor.setKeepAliveSeconds(keepAliveSeconds);
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.setThreadNamePrefix(getThreadNamePrefix());
        executor.initialize();
        return executor;
    }
}

配置文件

executor:
    corePoolSize: 5
    maxPoolSize: 10
    queueCapacity: 20
    keepAliveSeconds: 60
    threadNamePrefix: XCExecutor-
  • 在SpringBoot启动类上增加@EnableAsync注解
  • 然后再需要多线程执行的方法上增加@Async(value = "taskAsyncPool")注解即可

线程池

线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后再创建线程后自动启动这些任务。

为什么使用线程池

一般使用线程的方式有两种:一种是继承Thread类,一种是实现Runnable的接口,Thread类也是实现了Runnable接口。这两种方式在运行接收后都会被虚拟机销毁。如果线程数量多的话,频繁的创建和销毁就会大大的浪费时间和效率,而且会浪费内存。为了减少创建和销毁线程的次数,让每个线程可以多次使用,可根据系统情况调整执行的线程数量,防止消耗过多内存和是时间。
一个线程池包括以下四个基本部分:

  • 线程池管理器(ThreadPool) : 用于创建并管理线程池,包括销毁线程池和添加新任务
  • 工作线程(PoolWorker) : 线程池中线程,在没有任务时处于等待装态,主要循环执行的任务
  • 任务接口(Task) : 每个任务都必须实现的接口,以供工作线程调度任务的执行,主要规定了任务的入口,任务执行完后的收尾工作,以及任务的执行装态等
  • 任务队列(taskQueue) : 用于存放没有处理的任务。一种缓冲机制。

特点

  • 线程复用
  • 控制最大并发数量
  • 管理线程

优点

  • 降低了资源消耗。通过复用机制降低了线程的创建和销毁带来的消耗
  • 提高响应速度。当任务来临时,不需要等待创建线程的时间就能立即执行
  • 提高线程的管理。如果无限制的创建,不仅消耗系统资源,还会降低系统的稳定性,使用线程池可以统一分配,调优和控制

线程池配置说明

线程池的最上层接口是Executor,这个接口定义了一个核心方法execute(Runnable command),这个方法最后被ThreadPoolExecutor类实现,用来传入任务。而且ThreadPoolExecutor是线程池的核心类,此类构造方法如下:

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.acc = System.getSecurityManager() == null ?
                null :
                AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }
  • corePoolSize:核心线程池的大小,如果核心线程池有空闲位置,这是新的任务就会被核心线程池新建一个线程执行,执行完毕后不会销毁线程,线程会进入缓存队列等待再次被运行。
  • maximumPoolSize:线程池能创建最大的线程数量。如果核心线程池和缓存队列都已经满了,新的任务进来就会创建新的线程来执行。但是数量不能超过maximunPoolSize,否侧会采取拒绝接受任务策略,我们下面会具体分析。
  • keepAliveTime:非核心线程能够空闲的最长时间,超过时间,线程终止。这个参数默认只有在线程数量超过核心线程池大小时才会起作用。只要线程数量不超过核心线程大小,就不会起作用。
  • unit:时间单位,和keepAliveTime配合使用。
  • workQueue:缓存队列,用来存放等待被执行的任务。
  • threadFactory:线程工厂,用来创建线程,一般有三种选择策略。
  • ArrayBlockingQueue
  • LinkedBlockingQueue
  • SynchronousQueue
  • handler:拒绝处理策略,线程数量大于最大线程数就会采用拒绝处理策略
  • ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
  • ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
  • ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
  • ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务
  • 实现RejectedExecutionHandler接口,也可自定义处理器。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,658评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,482评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,213评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,395评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,487评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,523评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,525评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,300评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,753评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,048评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,223评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,905评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,541评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,168评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,417评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,094评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,088评论 2 352

推荐阅读更多精彩内容

  • 转自http://www.cnblogs.com/dolphin0520/p/3932921.html Java并...
    Allen_cyn阅读 1,905评论 0 4
  • Java并发编程:线程池的使用 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会...
    逗逼程序员阅读 447评论 0 2
  • 原文连接 在前面的文章中,我们使用线程的时候就去创建一个线程,这样实现起来非常简便,但是就会有一个问题: 如果并发...
    zjk_00阅读 633评论 0 1
  • 前段时间遇到这样一个问题,有人问微信朋友圈的上传图片的功能怎么做才能让用户的等待时间较短,比如说一下上传9张图片,...
    加油码农阅读 1,194评论 0 2
  • 芽儿尖了 草儿浅了 堤柳笼烟 花事待传 盈盈顾盼 钓一池清浅 书一个早字 我在院中念 花儿艳了 风儿俏了 山色暮岚...
    简斋茶悦阅读 93评论 2 2