Maison >Java >javaDidacticiel >À quoi devons-nous faire attention lors du développement multi-threads sous Springboot ? (Résumer)
Cet article vous apporte ce à quoi vous devez faire attention lors du développement multi-threads sous springboot ? (Résumé), il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer. J'espère qu'il vous sera utile.
Dans le processus de développement de programmes multithread basés sur springboot, les avantages de springboot ne peuvent être exercés que parce que le conteneur spring lui-même doit être injecté pour la gestion. Par conséquent, cet article est principalement utilisé pour enregistrer certains points auxquels il faut prêter attention lors de la combinaison des deux au cours du développement.
Dans la première étape, nous injectons l'instance de la classe thread dans le conteneur sping pour la gestion
@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{ }
Ici, nous utilisons le springboot @Import annotation et put ThreadConfig Des exemples d'annotations dans les packages analysés ici, tels que @Component, etc., sont injectés dans le conteneur Spring
Ensuite, le fil est démarré. Il y a deux situations dans mon entreprise. scénario :
1. Lorsque le programme est en cours d'exécution, il démarre automatiquement
Il s'agit d'un programme exécutable général. Bien sûr, il peut être exécuté directement dans la fonction principale pour démarrer le thread. grâce au code. Mais dans Springboot, nous pouvons utiliser l'annotation @PostConstruct pour permettre à l'objet thread qui a été injecté dans le conteneur du bean de démarrer automatiquement
@Component public class demoThread extends Thread { //注意这里,如果你没有实现把多线程类的实例注入到spring容器中,这里你是无法拿到其他自动装配的对象实例的的,这也是我们第一步的意义所在。 @Autowired private XxxService xxxService; @PostConstruct public void start() { super.start(); } public void run() { // Ok,在这里你就可以实现线程要实现的功能逻辑了,自然也可以直接使用装配好的sevice对象实例。 } }
2. Dans le programme, démarré lorsque les threads doivent être ouverts, comme la réception de données de kafka et le démarrage du traitement des threads, bien sûr, dans ce cas, vous devez également passer par la première étape et injecter l'instance de classe thread dans le conteneur 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 ThreadLocalc0f559cc8d56b43654fcbe4aa9df7b4a valueLocal = new ThreadLocal 46fc8f240055341038a5bc0c386009d9 () { @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; } }Ici, nous devons faire attention à savoir si la classe de thread TaskThread doit être ajoutée avec le @Scope (" prototype") dans spirngboot et défini sur le mode multi-instances ou sur le modèle Singleton par défaut.
En mode singleton, SpringBootUtils.getBean(TaskThread.class) renvoie le même objet à chaque fois. Bien qu'il ne soit pas nécessaire de créer un nouvel objet à chaque fois, le thread de la variable membre ne peut pas être garanti. . La sécurité, c'est-à-dire que les valeurs des threads d'exécution dans le pool de threads sont partagées. En mode multi-instance, puisqu'un nouvel objet thread est créé à chaque fois, le problème ci-dessus n'existe pas.
Alors s'il vous plaît faites attention ici, qu'il s'agisse de mon exemple de code ci-dessus ou d'un développement Web ordinaire, spirngboot est par défaut en mode singleton et les variables membres personnalisées ne sont pas sécurisées pour les threads. via ThreadLocal ou d’autres méthodes.
Retour à notre scénario commercial actuel, ici nous avons besoin que chaque thread traite différentes valeurs sans s'affecter les unes les autres, puis définissez le TaskThread sur plusieurs instances via le modèle d'annotation @Scope("prototype") . RésuméÀ travers l'exemple ci-dessus, nous pouvons voir que la combinaison de springboot et de multi-threading est relativement simple. Grâce à la configuration, nous pouvons gérer les classes de thread dans le conteneur Spring et également dans les threads. . Utilisez l'instance d'objet dans le conteneur SPING. Dans le même temps, nous devons consciemment prêter attention aux problèmes de sécurité des threads et aux problèmes de mécanisme de fonctionnement interne pendant l'utilisation. Bien sûr, la compréhension ici reste relativement simple. S'il y a quelque chose d'incorrect, veuillez le signaler et l'expliquer.Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!