基于springboot的多线程程序开发过程中,由于本身也需要注入spring容器进行管理,才能发挥springboot的优势。所以这篇文字主要用来记录开发中两者结合时需要注意的一些事项。

第一步我们把线程类的实例注入sping容器进行管理

  1. @Configuration
  2. @SpringBootApplication
  3. @Import({ThreadConfig.class})
  4. public class ThreadApp implements CommandLineRunner
  5. {
  6. public static void main(String[] args) throws Exception {
  7.  
  8. ApplicationContext app = SpringApplication.run(ThreadApp .class, args);
  9. //这里主要保存上下文对象实例,需要加上。SpringBootUtils类网上很多,可以自己搜下
  10. SpringBootUtils.setApplicationContext(app);
  11.  
  12. }
  13.  
  14. //access command line arguments
  15. @Override
  16. public void run(String... args) throws Exception {
  17. //do something
  18. }
  19. }
  20.  
  21. //ComponentScan注解会扫描com.demo.thead下,也就是多线程类所在的包下的文件
  22. @Configuration
  23. @ComponentScan(basePackages = { "com.demo.thread"})
  24. public class ThreadConfig{
  25.  
  26. }

这里使用springboot @Import 注解,把ThreadConfig里扫描到的包中带注解的示例,如@Component等注入到spring容器当中.

然后是线程的启动,这里在我的业务场景中有两种情况:

1、程序运行时,自动启动;

这在一般的可执行程序里面,当然可以直接在main函数里执行通过代码启动线程。但在springboot中,我们可以使用@PostConstruct注解的方式,让已经注入bean容器的线程对象自启动

  1. @Component
  2. public class demoThread extends Thread
  3. {
  4. //注意这里,如果你没有实现把多线程类的实例注入到spring容器中,这里你是无法拿到其他自动装配的对象实例的的,这也是我们第一步的意义所在。
  5. @Autowired
  6. private XxxService xxxService;
  7.  
  8. @PostConstruct
  9. public void start() {
  10. super.start();
  11. }
  12.  
  13. public void run() {
  14. // Ok,在这里你就可以实现线程要实现的功能逻辑了,自然也可以直接使用装配好的sevice对象实例。
  15.  
  16. }
  17. }

2、在程序中,需要开启线程时启动,比如在从kafka接收数据,开启线程处理,当然这种情况下也需要通过第一步,把线程类实例注入到sping容器中

  1. private TaskThread thread;
  2. private ExecutorService taskPool= new ThreadPoolExecutor(
  3. 5, 10, 1000,
  4. TimeUnit.MILLISECONDS, new ArrayBlockingQueue<>(10),
  5. new ThreadPoolExecutor.CallerRunsPolicy());
  6.  
  7. @KafkaListener(topics = "xxTopic")
  8. public void receive(ConsumerRecord<Object, Object> consumerRecord) {
  9. JSONObject json = JSON.parseObject(consumerRecord.value().toString());
  10. //通过SpringBootUtils获取线程类的实例
  11. thread = SpringBootUtils.getBean(TaskThread.class);
  12. //启动线程
  13. //new Thread(thread).start() ;
  14. //向线程对象里传值
  15. thread.init(i);
  16. //放入线程池执行
  17. taskPool.execute(thread);
  18.  
  19. }
  1. //注意这里是否添加@Scope("prototype")注解
  2. @Component
  3. @Scope("prototype")
  4. public class TaskThread implements Runnable{
  5.  
  6. protected int value=0
  7.  
  8. @Autowired
  9. private XxxService xxxService;
  10.  
  11. //ThreadLocal 对象,单例模式下可以保证成员变量的线程安全和独立性。
  12. public ThreadLocal<Integer> valueLocal = new ThreadLocal < Integer > () {
  13. @Override
  14. protected Integer initialValue() {
  15. return 0;
  16. }
  17. };
  18.  
  19. protected static final Logger LOG = LoggerFactory.getLogger(GpsTaskThread.class);
  20.  
  21. @Override
  22. public final void run() {
  23. try {
  24. LOG.info(value+"");
  25.  
  26. } catch (Exception e) {
  27. // TODO Auto-generated catch block
  28. e.printStackTrace();
  29. }
  30. }
  31.  
  32. public void init(int Value) {
  33. this.value=Value;
  34. }
  35.  
  36. }

在这里我们需要注意,TaskThread这个线程类在spirngboot中是否要添加@Scope("prototype")注解设置为多例模式还是默认单例模式。

在单例模式下SpringBootUtils.getBean(TaskThread.class) 每次返回的都是同一个对象,虽然不需要每次都创建新的对象,但无法保证成员变量的线程安全,也就是说在线程池中的执行的线程,它们的value值是共享的。而多例模式下,由于每次创建的都是一个新的线程对象,则不存在上述问题。

所以在这里请大家注意无论是我上面的示例代码还是平常的web开发中,spirngboot默认为单例模式,自定义的成员变量是线程不安全的,需要通过ThreadLocal 或这其他方法做同步处理。

回到我们当前的业务场景,在这里我们需要每个线程处理的value值不同,互不影响,那么通过@Scope("prototype")注解把TaskThread设置为多例模式。

总结

通过上面的示例,我们可以看到springboot与多线程的结合还是比较简单,通过配置,我们既可以在spring容器中管理线程类,也可以在线程中使用sping容器中的对象实例。同时我们在使用的过程当中要有意识的去注意线程安全方面的问题和内部运行机制的问题。当然这里理解的还是比较浅显,如果有不正确的地方还请大家指出与海涵。

关注微信公众号,查看更多技术文章。

springboot下多线程开发注意事项的更多相关文章

  1. Delphi多线程开发注意事项

    Q1: 多线程中需避免多个线程同时向全局变量进行写入操作,导致访问冲突问题. A1:  可以通过使用加锁机制(比如:临界区.互斥.信号量)解决此问题. Q2:多线程中对于结构体和CLASS类型的全局变 ...

  2. Linux下c开发 之 线程通信(转)

    Linux下c开发 之 线程通信(转) 1.Linux“线程” 进程与线程之间是有区别的,不过Linux内核只提供了轻量进程的支持,未实现线程模型.Linux是一种“多进程单线程”的操作系统.Linu ...

  3. Java进阶(三)多线程开发关键技术

    原创文章,同步发自作者个人博客,转载请务必以超链接形式在文章开头处注明出处http://www.jasongj.com/java/multi_thread/. sleep和wait到底什么区别 其实这 ...

  4. Linux下c开发 之 线程通信

    Linux下c开发 之 线程通信 1.Linux“线程” 进程与线程之间是有区别的,不过Linux内核只提供了轻量进程的支持,未实现线程模型.Linux是一种“多进程单线程”的操作系统.Linux本身 ...

  5. .NET基础拾遗(5)多线程开发基础

    Index : (1)类型语法.内存管理和垃圾回收基础 (2)面向对象的实现和异常的处理基础 (3)字符串.集合与流 (4)委托.事件.反射与特性 (5)多线程开发基础 (6)ADO.NET与数据库开 ...

  6. Java多线程开发系列之番外篇:事件派发线程---EventDispatchThread

    事件派发线程是java Swing开发中重要的知识点,在安卓app开发中,也是非常重要的一点.今天我们在多线程开发中,穿插进来这个线程.分别从线程的来由.原理和使用方法三个方面来学习事件派发线程. 一 ...

  7. Java多线程开发系列之四:玩转多线程(线程的控制2)

    在上节的线程控制(详情点击这里)中,我们讲解了线程的等待join().守护线程.本节我们将会把剩下的线程控制内容一并讲完,主要内容有线程的睡眠.让步.优先级.挂起和恢复.停止等. 废话不多说,我们直接 ...

  8. Java多线程开发系列之一:走进多线程

    对编程语言的基础知识:分支.选择.循环.面向对象等基本概念理解后,我们需要对java高级编程有一定的学习,这里不可避免的要接触到多线程开发. 由于多线程开发整体的系统比较大,我会写一个系列的文章总结介 ...

  9. Java之多线程开发时多条件Condition接口的使用

    转:http://blog.csdn.net/a352193394/article/details/39454157 我们在多线程开发中,可能会出现这种情况.就是一个线程需要另外一个线程满足某某条件才 ...

随机推荐

  1. js - 如何使子元素阻止继承父元素事件

    想要阻止点击 #content 区域时触发a事件,需要在 #content 区域内加入阻止事件冒泡的代码,具体代码如下: <div id="box" onclick=&quo ...

  2. BF字符串匹配算法

    Brute Force算法是普通的模式匹配算法,BF算法的思想就是将目标串S的第一个字符与模式串T的第一个字符进行匹配,若相等,则继续比较S的第二个字符和 T的第二个字符: 若不相等,则比较S的第二个 ...

  3. PHPweb应用攻击总结(转)

    XSS跨站脚本 概念:恶意攻击者往Web页面里插入恶意html代码,当用户浏览该页之时,嵌入其中Web里面的html代码会被执行,从而达到恶意用户的特殊目的. 危害: 盗取用户COOKIE信息. 跳转 ...

  4. tf.contrib.rnn.core_rnn_cell.BasicLSTMCell should be replaced by tf.contrib.rnn.BasicLSTMCell.

    For Tensorflow 1.2 and Keras 2.0, the line tf.contrib.rnn.core_rnn_cell.BasicLSTMCell should be repl ...

  5. [LeetCode&Python] Problem 292. Nim Game

    You are playing the following Nim Game with your friend: There is a heap of stones on the table, eac ...

  6. javascript的this多种场景用法

    作者:刘志祥 时间:2017.11.10 参考:阮一峰的官方网站 this 是javaScript中的一个关键字,只能在函数内使用.随着场合的不同,this的值会发生变化. 1. 单纯的全局函数调用, ...

  7. C#动态创建Xml-LinQ方式

    C#创建Xml-LinQ方式 本文提供全流程,中文翻译. Chinar 坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar -- 心分享 ...

  8. tile38 server 密码保护

    默认tile38 是没有密码保护的,我们可以通过配置指定密码,类似redis 的,但是redis 的一般我们是配置在 配置文件中的 环境准备 docker-compose 文件   version: ...

  9. lerna import && add 使用&&常见问题解决

    使用lerna 的import 我们可以方便的将一个普通的npm 包倒入到lerna 管理的monorepo 中 环境准备 lerna init 注意必须是一个git 项目,同时需要commit ,不 ...

  10. 02HDFS架构

    https://www.cnblogs.com/zhoujingyu/p/5040957.html https://blog.csdn.net/firstchange/article/details/ ...