spring boot中多线程开发的注意事项总结

 更新时间:2018年09月25日 08:57:51   作者:bigfan  
spring boot 通过任务执行器 taskexecutor 来实现多线程和并发编程。下面这篇文章主要给大家介绍了关于spring boot中多线程开发的注意事项,文中通过示例代码介绍的非常详细,需要的朋友可以参考下

前言

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容器中的对象实例。同时我们在使用的过程当中要有意识的去注意线程安全方面的问题和内部运行机制的问题。当然这里理解的还是比较浅显,如果有不正确的地方还请大家指出与海涵。

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对脚本之家的支持。

相关文章

  • JavaWeb 实现验证码功能(demo)

    JavaWeb 实现验证码功能(demo)

    在 WEB-APP 中一般应用于:登录、注册、买某票、秒杀等场景,大家都接触过这个验证码操作,今天小编通过实例代码给大家讲解javaweb实现验证码功能,需要的朋友参考下
    2017-02-02
  • SpringBoot系列教程之dubbo和Zookeeper集成方法

    SpringBoot系列教程之dubbo和Zookeeper集成方法

    这篇文章主要介绍了SpringBoot系列教程之dubbo和Zookeeper集成方法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-09-09
  • spring boot中spring框架的版本升级图文教程

    spring boot中spring框架的版本升级图文教程

    Spring Boot是一款基于Spring框架的快速开发框架,它提供了一系列的开箱即用的功能和组件,这篇文章主要给大家介绍了关于spring boot中spring框架的版本升级的相关资料,需要的朋友可以参考下
    2023-10-10
  • 深入解析Java的Spring框架中bean的依赖注入

    深入解析Java的Spring框架中bean的依赖注入

    这篇文章主要介绍了Java的Spring框架中bean的依赖注入,讲解了以构造函数为基础的依赖注入和基于setter方法的依赖注入的方式,需要的朋友可以参考下
    2015-12-12
  • Java的三种代理模式简述

    Java的三种代理模式简述

    这篇文章主要简述Java的三种代理模式,java的代理模式主要包括静态代理、动态代理、Cglib代理,感兴趣的小伙伴可以参考下面文章的具体内容
    2021-09-09
  • 浅谈MyBatis循环Map(高级用法)

    浅谈MyBatis循环Map(高级用法)

    这篇文章主要介绍了浅谈MyBatis循环Map(高级用法),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-09-09
  • SpringBoot应用刚启动时服务报大量超时的问题及解决

    SpringBoot应用刚启动时服务报大量超时的问题及解决

    在Java项目上线过程中,经常遇到的超时问题主要是由于JVM的JIT编译导致,JIT(Just-In-Time)编译是Java虚拟机的一项技术,用于提高Java应用的性能,它通过将热点代码(频繁执行的部分)转换成本地机器码来优化执行效率
    2024-11-11
  • 解决Javaweb 提交表单到servlet时出现空白页面,但网站不报错问题

    解决Javaweb 提交表单到servlet时出现空白页面,但网站不报错问题

    这篇文章主要介绍了解决Javaweb 提交表单到servlet时出现空白页面,但网站不报错的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-08-08
  • 详解如何通过Java实现类似Nginx代理

    详解如何通过Java实现类似Nginx代理

    最近遇到一个问题,在内网环境中部署的项目需要调用外网完成一些应用,一般情况我们可以通过增加一台机器,部署到可以访问外网的服务器上,然后内网直接连接该机器通过Nginx进行代理即可,所以本文介绍了如何通过Java实现类似Nginx代理,需要的朋友可以参考下
    2024-08-08
  • 超详细的Spring Boot入门笔记(总结)

    超详细的Spring Boot入门笔记(总结)

    本篇文章主要介绍了超详细的Spring Boot入门笔记(总结),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-11-11

最新评论