spring boot中多线程开发的注意事项总结
作者:bigfan 发布时间:2022-03-14 19:20:07
前言
Springt通过任务执行器(TaskExecutor)来实现多线程和并发编程。使用ThreadPoolTaskExecutor可实现一个基于线程池的TaskExecutor。而实际开发中任务一般是非阻碍的,即异步的,所以我们要在配置类中通过@EnableAsync 开启对异步任务的支持,并通过实际执行Bean的方法中使用@Async注解来声明其是一个异步任务。
基于springboot的多线程程序开发过程中,由于本身也需要注入spring容器进行管理,才能发挥springboot的优势。所以这篇文字主要用来记录开发中两者结合时需要注意的一些事项。
注意事项
第一步我们把线程类的实例注入sping容器进行管理
@Configuration
@SpringBootApplication
@Import({ThreadConfig.class})
public class ThreadApp implements CommandLineRunner
{
public static void main(String[] args) throws Exception {
ApplicationContext app = SpringApplication.run(ThreadApp .class, args);
//这里主要保存上下文对象实例,需要加上。SpringBootUtils类网上很多,可以自己搜下
SpringBootUtils.setApplicationContext(app);
}
//access command line arguments
@Override
public void run(String... args) throws Exception {
//do something
}
}
//ComponentScan注解会扫描com.demo.thead下,也就是多线程类所在的包下的文件
@Configuration
@ComponentScan(basePackages = { "com.demo.thread"})
public class ThreadConfig{
}
这里使用springboot @Import 注解,把ThreadConfig里扫描到的包中带注解的示例,如@Component等注入到spring容器当中.
然后是线程的启动,这里在我的业务场景中有两种情况:
1、程序运行时,自动启动;
这在一般的可执行程序里面,当然可以直接在main函数里执行通过代码启动线程。但在springboot中,我们可以使用@PostConstruct注解的方式,让已经注入bean容器的线程对象自启动
@Component
public class demoThread extends Thread
{
//注意这里,如果你没有实现把多线程类的实例注入到spring容器中,这里你是无法拿到其他自动装配的对象实例的的,这也是我们第一步的意义所在。
@Autowired
private XxxService xxxService;
@PostConstruct
public void start() {
super.start();
}
public void run() {
// Ok,在这里你就可以实现线程要实现的功能逻辑了,自然也可以直接使用装配好的sevice对象实例。
}
}
2、在程序中,需要开启线程时启动,比如在从kafka接收数据,开启线程处理,当然这种情况下也需要通过第一步,把线程类实例注入到sping容器中
private TaskThread thread;
private ExecutorService taskPool= new ThreadPoolExecutor(
5, 10, 1000,
TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(10),
new ThreadPoolExecutor.CallerRunsPolicy());
@KafkaListener(topics = "xxTopic")
public void receive(ConsumerRecord<Object, Object> consumerRecord) {
JSONObject json = JSON.parseObject(consumerRecord.value().toString());
//通过SpringBootUtils获取线程类的实例
thread = SpringBootUtils.getBean(TaskThread.class);
//启动线程
//new Thread(thread).start() ;
//向线程对象里传值
thread.init(i);
//放入线程池执行
taskPool.execute(thread);
}
//注意这里是否添加@Scope("prototype")注解
@Component
@Scope("prototype")
public class TaskThread implements Runnable{
protected int value=0;
@Autowired
private XxxService xxxService;
//ThreadLocal 对象,单例模式下可以保证成员变量的线程安全和独立性。
public ThreadLocal<Integer> valueLocal = new ThreadLocal < Integer > () {
@Override
protected Integer initialValue() {
return 0;
}
};
protected static final Logger LOG = LoggerFactory.getLogger(GpsTaskThread.class);
@Override
public final void run() {
try {
LOG.info(value+"");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void init(int Value) {
this.value=Value;
}
}
在这里我们需要注意,TaskThread这个线程类在spirngboot中是否要添加@Scope("prototype")
注解设置为多例模式还是默认单例模式。
在单例模式下SpringBootUtils.getBean(TaskThread.class)
每次返回的都是同一个对象,虽然不需要每次都创建新的对象,但无法保证成员变量的线程安全,也就是说在线程池中的执行的线程,它们的value值是共享的。而多例模式下,由于每次创建的都是一个新的线程对象,则不存在上述问题。
所以在这里请大家注意无论是我上面的示例代码还是平常的web开发中,spirngboot默认为单例模式,自定义的成员变量是线程不安全的,需要通过ThreadLocal 或这其他方法做同步处理。
回到我们当前的业务场景,在这里我们需要每个线程处理的value值不同,互不影响,那么通过@Scope("prototype")
注解把TaskThread设置为多例模式。
总结
通过上面的示例,我们可以看到springboot与多线程的结合还是比较简单,通过配置,我们既可以在spring容器中管理线程类,也可以在线程中使用sping容器中的对象实例。同时我们在使用的过程当中要有意识的去注意线程安全方面的问题和内部运行机制的问题。当然这里理解的还是比较浅显,如果有不正确的地方还请大家指出与海涵。
好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对脚本之家的支持。
来源:https://www.cnblogs.com/dafanjoy/p/9692841.html
猜你喜欢
- 前言作为一个开发者,日常会接触到很多优秀的软件,其实,或多或少会有这样的想法,我能不能开发一个自己软件,甚至办公软件都希望是Markdown
- 前言本篇文章将教你作为一个.NET程序员如何快入门Spring Boot。你不需要用Eclipse,也不需要用IDEA。已经习惯了VS,其他
- kafka 架构原理大数据时代来临,如果你还不知道Kafka那就真的out了!据统计,有三分之一的世界财富500强企业正在使用K
- 本文实例讲述了Java实现过滤掉map集合中key或value为空的值。分享给大家供大家参考,具体如下:import java.util.C
- 一、volatile关键字介绍及底层原理1.volatile的特性(内存语义)当一个变量被定义成volatile之后,它将具备两项特性:第一
- 有时候我们需要多列表中的数据进行特定的排序,最近项目中用到的是按名称排序,所以简单来说一下:效果图:排序方法:Collections.sor
- java 中基本算法之希尔排序的实例详解希尔排序(Shell Sort)是插入排序的一种。也称缩小增量排序,是直接插入排序算法的一种更高效的
- 路由事件模型传统的简单事件模型中,在消息激发是将消息通过事件订阅的然后交给事件的相应者,事件的相应者使用事件的处理器来做出相应,这样就存在一
- SpringBoot访问外部文件及默认路由1 新增配置类package com.pibigstar.common.config;import
- 一、概述无论是什么语言,在多线程编程中,常常会遇到多个线同时操作程某个变量(读/写),如果读/写不同步,则会造成不符合预期的结果。例如:线程
- 本文实例为大家分享了SpringBoot获取yml和properties配置文件的具体代码,供大家参考,具体内容如下(一)yml配置文件:p
- 一、技术介绍线上演示地址:http://chat.breez.work实时通信(Instant Messaging,简称IM)是一个实时通信
- 在Java解析XML文件的过程中,有时需要获取符合某些特定条件的节点,以下是实现代码。import javax.xml.xpath.XPat
- 本文实例讲述了java实现切割wav音频文件的方法。分享给大家供大家参考,具体如下:import it.sauronsoftware.jav
- UGUI的滑动组件虽然表现上和NGUI的ScrollView一致,但是它更美好的是开放源码的,不了解原理的时候直接查源码就OK。在使用Scr
- 本文实例讲述了C#在WinForm中使用WebKit传递js对象实现与网页交互的方法。分享给大家供大家参考,具体如下:有个项目要使用WebB
- 当目标数据库不能直连的,需要一个服务器作为中间跳板的时候,我们需要通过SSH通道连接数据库。ps:使用ssh连接,相当于本地开了个端口去连接
- 唉!我还真是在面试中学习新东东啊,一个公司刚刚给了个测试,不过我很奇怪的是为什么web developer的职位居然考java的反射机制题,
- 1: .net framework 由两个部分组成:CLR 和 FCL。2:在CLR中,所有错误都是通过异常来报告的。3:智能感知功能主要是
- 定义在一幅无向图G=(V,E) 中,(u,v) 为连接顶点u和顶点v的边,w(u,v)为边的权重,若存在边的子集T&am