springboot 项目中创建线程池-mile米乐体育
前言:
前两天做项目的时候,想提高一下插入表的性能优化,因为是两张表,先插旧的表,紧接着插新的表,一万多条数据就有点慢了
后面就想到了线程池
threadpoolexecutor
,而用的是spring boot项目,可以用spring提供的对threadpoolexecutor
封装的线程池threadpooltaskexecutor
,直接使用注解启用
使用步骤:
先创建一个线程池的配置,让spring boot加载,用来定义如何创建一个threadpooltaskexecutor
,要使用@configuration
和@enableasync
这两个注解,表示这是个配置类,并且是线程池的配置类
@configuration @enableasync publicclassexecutorconfig{ privatestaticfinalloggerlogger=loggerfactory.getlogger(executorconfig.class); @value("${async.executor.thread.core_pool_size}") privateintcorepoolsize; @value("${async.executor.thread.max_pool_size}") privateintmaxpoolsize; @value("${async.executor.thread.queue_capacity}") privateintqueuecapacity; @value("${async.executor.thread.name.prefix}") privatestringnameprefix; @bean(name="asyncserviceexecutor") publicexecutorasyncserviceexecutor(){ logger.info("startasyncserviceexecutor"); threadpooltaskexecutorexecutor=newthreadpooltaskexecutor(); //配置核心线程数 executor.setcorepoolsize(corepoolsize); //配置最大线程数 executor.setmaxpoolsize(maxpoolsize); //配置队列大小 executor.setqueuecapacity(queuecapacity); //配置线程池中的线程的名称前缀 executor.setthreadnameprefix(nameprefix); // rejection-policy:当pool已经达到max size的时候,如何处理新任务 // caller_runs:不在新线程中执行任务,而是有调用者所在的线程来执行 executor.setrejectedexecutionhandler(newthreadpoolexecutor.callerrunspolicy()); //执行初始化 executor.initialize(); returnexecutor; } }
@value
是我配置在application.properties
,可以参考配置,自由定义
>推荐下自己做的 spring cloud 的实战项目: > >
创建一个service接口,是异步线程的接口
publicinterfaceasyncservice{ /***执行异步任务*可以根据需求,自己加参数拟定,我这里就做个测试演示*/ voidexecuteasync(); }
实现类:
@service publicclassasyncserviceimplimplementsasyncservice{ privatestaticfinalloggerlogger=loggerfactory.getlogger(asyncserviceimpl.class); @override @async("asyncserviceexecutor") publicvoidexecuteasync(){ logger.info("startexecuteasync"); system.out.println("异步线程要做的事情"); system.out.println("可以在这里执行批量插入等耗时的事情"); logger.info("endexecuteasync"); } }
将service层的服务异步化,在executeasync()
方法上增加注解@async("asyncserviceexecutor")
,asyncserviceexecutor
方法是前面executorconfig.java中的方法名,表明executeasync
方法进入的线程池是asyncserviceexecutor
方法创建的
接下来就是在controller里或者是哪里通过注解@autowired
注入这个service
@autowired privateasyncserviceasyncservice; @getmapping("/async") publicvoidasync(){ asyncservice.executeasync(); }
用postmain或者其他工具来多次测试请求一下
2018-07-1622:15:47.655info10516---[async-service-5]c.u.d.e.executor.impl.asyncserviceimpl:startexecuteasync
异步线程要做的事情
可以在这里执行批量插入等耗时的事情
2018-07-1622:15:47.655info10516---[async-service-5]c.u.d.e.executor.impl.asyncserviceimpl:endexecuteasync
2018-07-1622:15:47.770info10516---[async-service-1]c.u.d.e.executor.impl.asyncserviceimpl:startexecuteasync
异步线程要做的事情
可以在这里执行批量插入等耗时的事情
2018-07-1622:15:47.770info10516---[async-service-1]c.u.d.e.executor.impl.asyncserviceimpl:endexecuteasync
2018-07-1622:15:47.816info10516---[async-service-2]c.u.d.e.executor.impl.asyncserviceimpl:startexecuteasync
异步线程要做的事情
可以在这里执行批量插入等耗时的事情
2018-07-1622:15:47.816info10516---[async-service-2]c.u.d.e.executor.impl.asyncserviceimpl:endexecuteasync
2018-07-1622:15:48.833info10516---[async-service-3]c.u.d.e.executor.impl.asyncserviceimpl:startexecuteasync
异步线程要做的事情
可以在这里执行批量插入等耗时的事情
2018-07-1622:15:48.834info10516---[async-service-3]c.u.d.e.executor.impl.asyncserviceimpl:endexecuteasync
2018-07-1622:15:48.986info10516---[async-service-4]c.u.d.e.executor.impl.asyncserviceimpl:startexecuteasync
异步线程要做的事情
可以在这里执行批量插入等耗时的事情
2018-07-1622:15:48.987info10516---[async-service-4]c.u.d.e.executor.impl.asyncserviceimpl:endexecuteasync
通过以上日志可以发现,[async-service-]
是有多个线程的,显然已经在我们配置的线程池中执行了,并且每次请求中,controller的起始和结束日志都是连续打印的,表明每次请求都快速响应了,而耗时的操作都留给线程池中的线程去异步执行;
虽然我们已经用上了线程池,但是还不清楚线程池当时的情况,有多少线程在执行,多少在队列恰卡编程网中等待呢?这里我创建了一个threadpooltaskexecutor的子类,在每次提交线程的时候都会将当前线程池的运行状况打印出来
importorg.slf4j.logger; importorg.slf4j.loggerfactory; importorg.springframework.scheduling.concurrent.threadpooltaskexecutor; importorg.springframework.util.concurrent.listenablefuture; importjava.util.concurrent.callable; importjava.util.concurrent.future; importjava.util.concurrent.threadpoolexecutor; /***@author:chenbin*@date:2018/7/16/001622:19*/ publicclassvisiablethreadpooltaskexecutorextendsthreadpooltaskexecutor{ privatestaticfinalloggerlogger=loggerfactory.getlogger(visiablethreadpooltaskexecutor.class); privatevoidshowthreadpoolinfo(stringprefix){ threadpoolexecutorthreadpoolexecutor=getthreadpoolexecutor(); if(null==threadpoolexecutor){ return; } logger.info("{},{},taskcount[{}],completedtaskcount[{}],activecount[{}],queuesize[{}]", this.getthreadnameprefix(), prefix, threadpoolexecutor.gettaskcount(), threadpoolexecutor.getcompletedtaskcount(), threadpoolexecutor.getactivecount(), threadpoolexecutor.getqueue().size()); } @override publicvoidexecute(runnabletask){ showthreadpoolinfo("1.doexecute"); super.execute(task); } @override publicvoidexecute(runnabletask,longstarttimeout){ showthreadpoolinfo("2.doexecute"); super.execute(task,starttimeout); } @override publicfuturesubmit(runnabletask){ showthreadpoolinfo("1.dosubmit"); returnsuper.submit(task); } @override public
如上所示,showthreadpoolinfo方法中将任务总数、已完成数、活跃线程数,队列大小都打印出来了,然后override了父类的execute、submit等方法,在里面调用showthreadpoolinfo方法,这样每次有任务被提交到线程池的时候,都会将当前线程池的基本情况打印到日志中;
修改executorconfig.java
的asyncserviceexecutor
方法,将threadpooltaskexecutor executor = new threadpooltaskexecutor()
改为threadpooltaskexecutor executor = new visiablethreadpooltaskexecutor()
@bean(name="asyncserviceexecutor") publicexecutorasyncserviceexecutor(){ logger.info("startasyncserviceexecutor"); //在这里修改 threadpooltaskexecutorexecutor=newvisiablethreadpooltaskexecutor(); //配置核心线程数 executor.setcorepoolsize(corepoolsize); //配置最大线程数 executor.setmaxpoolsize(maxpoolsize); //配置队列大小 executor.setqueuecapacity(queuecapacity); //配置线程池中的线程的名称前缀 executor.setthreadnameprefix(nameprefix); // rejection-policy:当pool已经达到max size的时候,如何处理新任务 // caller_runs:不在新线程中执行任务,而是有调用者所在的线程来执行 executor.setrejectedexecutionhandler(newthreadpoolexecutor.callerrunspolicy()); //执行初始化 executor.initialize(); returnexecutor; }
再次启动该工程测试
2018-07-1622:23:30.951info14088---[nio-8087-exec-2]u.d.e.e.i.visiablethreadpooltaskexecutor:async-service-,2.dosubmit,taskcount[0],completedtaskcount[0],activecount[0],queuesize[0]
2018-07-1622:23:30.952info14088---[async-service-1]c.u.d.e.executor.impl.asyncserviceimpl:startexecuteasync
异步线程要做的事情
可以在这里执行批量插入等耗时的事情
2018-07-1622:23:30.953 恰卡编程网;info14088---[async-service-1]c.u.d.e.executor.impl.asyncserviceimpl:endexecuteasync
2018-07-1622:23:31.351info14088---[nio-8087-exec-3]u.d.e.e.i.visiablethreadpooltaskexecutor:async-service-,2.dosubmit,taskcount[1],completedtaskcount[1],activecount[0],queuesize[0]
2018-07-1622:23:31.353info14088---[async-service-2]c.u.d.e.executor.impl.asyncserviceimpl:startexecuteasync
异步线程要做的事情
可以在这里执行批量插入等耗时的事情
2018-07-1622:23:31.353info14088---[async-service-2]c.u.d.e.executor.impl.asyncserviceimpl:endexecuteasync
2018-07-1622:23:31.927info14088---[nio-8087-exec-5]u.d.e.e.i.visiablethreadpooltaskexecutor:async-service-,2.dosubmit,taskcount[2],completedtaskcount[2],activecount[0],queuesize[0]
2018-07-1622:23:31.929info14088---[async-service-3]c.u.d.e.executor.impl.asyncserviceimpl:startexecuteasync
异步线程要做的事情
可以在这里执行批量插入等耗时的事情
2018-07-1622:23:31.930info14088---[async-service-3]c.u.d.e.executor.impl.asyncserviceimpl:endexecuteasync
2018-07-1622:23:32.496info14088---[nio-8087-exec-7]u.d.e.e.i.visiablethreadpooltaskexecutor:async-service-,2.dosubmit,taskcount[3],completedtaskcount[3],activecount[0],queuesize[0]
2018-07-1622:23:32.498info14088---[async-service-4]c.u.d.e.executor.impl.asyncserviceimpl:startexecuteasync
异步线程要做的事情
可以在这里执行批量插入等耗时的事情
2018-07-1622:23:32.499info14088---[async-service-4]c.u.d.e.executor.impl.asyncserviceimpl:endexecuteasync
注意这一行日志:
2018-07-1622:23:32.496info14088---[nio-8087-exec-7]u.d.e.e.i.visiablethreadpooltaskexecutor:async-service-,2.dosubmit,taskcount[3],completedtaskcount[3],activecount[0],queuesize[0]
这说明提交任务到线程池的时候,调用的是submit(callable task)这个方法,当前已经提交了3个任务,完成了3个,当前有0个线程在处理任务,还剩0个任务在队列中等待,线程池的基本情况一路了然。
到此这篇关于springboot 项目中创建线程池的文章就介绍到这了,更多相关springboot 线程池内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!