Springt通过任务执行器(TaskExecutor)来实现多线程和并发编程。使用ThreadPoolTaskExecutor可实现一个基于线程池的TaskExecutor。而实际开发中任务一般是非阻碍的,即异步的,所以我们要在配置类中通过@EnableAsync开启对异步任务的支持,并通过实际执行Bean的方法中使用@Async注解来声明其是一个异步任务。
基于springboot的多线程程序开发过程中,由于本身也需要注入春容器进行管理,才能发挥springboot的优势,所以这篇文字主要用来记录开发中两者结合时需要注意的一些事项。
第一步我们把线程类的实例注入春容器进行管理
@ configuration @SpringBootApplication @ import ({ThreadConfig.class}) 公共类ThreadApp实现CommandLineRunner { 公共静态void main (String [] args){抛出异常 ApplicationContext应用=SpringApplication.run (ThreadApp . class, args);//这里主要保存上下文对象实例,需要加上.SpringBootUtils类网上很多,可以自己搜下 SpringBootUtils.setApplicationContext(应用); }//访问命令行参数 @Override 公共空间运行(字符串…args)抛出异常{//做某事 } }//ComponentScan注解会扫描com.demo.thead下,也就是多线程类所在的包下的文件 @ configuration @ComponentScan (basePackages={" com.demo.thread "}) 公开课ThreadConfig { }
这里使用springboot @ import注解,把ThreadConfig里扫描到的包中带注解的示例,如@ component等注入到春容器当中。
<>强然后是线程的启动,这里在我的业务场景中有两种情况:强>
1,程序运行时,自动启动;
这在一般的可执行程序里面,当然可以直接在主函数里执行通过代码启动线程。但在springboot中,我们可以使用@PostConstruct注解的方式,让已经注入bean容器的线程对象自启动
@ component 公开课demoThread延伸线 {//注意这里,如果你没有实现把多线程类的实例注入到春容器中,这里你是无法拿到其他自动装配的对象实例的的,这也是我们第一步的意义所在。 @ autowired 私人XxxService XxxService; @PostConstruct 公共空间开始(){ super.start (); } 公共空间run () {//好吧,在这里你就可以实现线程要实现的功能逻辑了,自然也可以直接使用装配好的服务对象实例。 } }
, 2,在程序中,需要开启线程时启动,比如在从卡夫卡接收数据,开启线程处理,当然这种情况下也需要通过第一步,把线程类实例注入到春容器中
私人TaskThread线程; 私人ExecutorService taskPool=new ThreadPoolExecutor ( 5,10,1000, TimeUnit。毫秒,新的ArrayBlockingQueue<祝辞(10), 新的ThreadPoolExecutor.CallerRunsPolicy ()); @KafkaListener(主题=皒xTopic”) 公共空间接收(ConsumerRecord<对象,Object>consumerRecord) { .toString JSONObject json=JSON.parseObject (consumerRecord.value () ());//通过SpringBootUtils获取线程类的实例 线程=SpringBootUtils.getBean (TaskThread.class);//启动线程//新线程(线程).start ();//向线程对象里传值 thread.init(我);//放入线程池执行 taskPool.execute(线程); }
//注意这里是否添加@Scope(“原型”)注解 @ component @Scope(“原型”) 公共类TaskThread实现Runnable { 受保护的int值=https://www.yisu.com/zixun/0; @ autowired 私人XxxService XxxService;//ThreadLocal对象,单例模式下可以保证成员变量的线程安全和独立性。 公共ThreadLocal <整数> valueLocal=new ThreadLocal <整数> (){ @Override 保护整数initialValue () { 返回0; } }; 保护静态最终记录器日志=LoggerFactory.getLogger (GpsTaskThread.class); @Override 公众最终无效run () { 尝试{ LOG.info(价值+ " "); }捕捉(异常e) {//TODO自动生成的catch块 e.printStackTrace (); } } 公共空间init (int值){ this.value=https://www.yisu.com/zixun/Value; } }
在这里我们需要注意,TaskThread这个线程类在spirngboot中是否要添加<代码> @Scope(“原型”)代码>注解设置为多例模式还是默认单例模式。
在单例模式下<代码> SpringBootUtils.getBean (TaskThread.class)