Aujourd'hui, nous apprendrons à effectuer des programmes asynchrones au printemps. Nous savons tous que les threads que le serveur Web traite request de demande sont obtenus à partir du pool de threads, ce qui n'est pas difficile à expliquer, car lorsque le nombre de demandes Web est très important, comment créer un thread de traitement lorsqu'une demande entre. Étant donné que les frais généraux de création de threads et de commutation de contexte de thread sont relativement importants, le serveur Web finira par faire face à un accident. De plus, les threads de traitement créés par le serveur Web sont exécutés de manière synchrone du début à la fin par défaut. C'est-à-dire que si le thread de traitement A est responsable du traitement de la demande B, alors lorsque B ne return pas, le thread de traitement A ne peut pas échapper pour traiter d'autres demandes, ce qui limitera considérablement la capacité de traitement simultanée du serveur Web.
Par conséquent, le pool de threads résout le problème du recyclage des threads, alors comment résoudre la demande de traitement synchrone? La réponse est un traitement asynchrone. Qu'est-ce que le traitement asynchrone? Le traitement asynchrone permet principalement que la demande B ci-dessus soit inactive avant la fin du traitement de la demande ci-dessus, et le thread A peut être libéré pour continuer à traiter d'autres demandes. Ensuite, nous pouvons le faire, redémarrer le thread C dans le thread A pour exécuter la tâche, laisser un retour directement sur le serveur Web et continuer à accepter de nouvelles demandes.
Avant de commencer l'explication ci-dessous, je distinguerai d'abord deux concepts ici:
1. Processus des threads
Le thread de traitement appartient au serveur Web, est responsable du traitement des demandes des utilisateurs et est géré par le pool de threads
2. Filation asynchrone
Les threads asynchrones sont des threads définis par l'utilisateur et peuvent être gérés par des pools de threads.
Spring prend en charge les tâches asynchrones. Les tâches asynchrones peuvent être implémentées à l'aide de la classe WebAsyncTask . Dans le même temps, nous pouvons également définir le traitement de rappel correspondant pour les tâches asynchrones, telles que la façon de gérer lorsque la tâche a expiré et comment lancer une exception. Les tâches asynchrones sont généralement très pratiques. Par exemple, nous voulons laisser une opération qui peut être traitée pendant longtemps au fil asynchrone pour traiter, ou lorsqu'une commande est payée, nous permettons à la tâche asynchrone de questionner le résultat de paiement de la commande.
1. Tâches asynchrones normales
Pour plus de commodité de démonstration, l'exécution des tâches asynchrones est simulée à l'aide de Thread.sleep(long) . Supposons maintenant que l'utilisateur demande l'interface suivante:
http://localhost:7000/demo/getUserWithNoThing.json
L'interface de tâche asynchrone est définie comme suit:
/ ** * tester des tâches asynchrones sans aucune exception * / @ requestmapping (value = "getuserwithnothing.json", méthode = requestMethod.get) webasynctask <string> getuserWithNothing () {// imprimer le nom de thread System.err.println ("Le nom de thread principal est" + thread.currentThread (). GetName ())) // Cela simule l'ouverture d'une tâche asynchrone, avec un délai d'expiration de 10s webaSyncTask <string> task1 = new webaSyncTask <string> (10 * 1000l, () -> {System.err.println ("Le premier nom de thread est" + thread.currentThread (). GetName ()); "La tâche 1 exécute avec succès! Aucune exception n'est lancée!"; // La méthode est appelée lorsque l'exécution de la tâche est terminée Task1.onCompletion (() -> {System.err.println ("Task 1 Exécute terminé!");}); System.err.println ("Task1 continue de gérer d'autres choses!"); Retour tâche1;}La console imprime comme suit:
Le nom du thread principal est http-nio-7000-exec-1
Task1 continue de traiter d'autres choses!
Le premier nom de thread est Mvcasync1
La tâche 1 est terminée!
Les résultats du navigateur sont les suivants:
2. Exception exceptionnelle tâche asynchrone
Appel d'interface: http://localhost:7000/demo/getUserWithError.json
/ ** * Testez la tâche asynchrone où une erreur se produit * @return * / @ requestmapping (value = "getuserwitherror.json", méthode = requestMethod.get) public webasyncTask <string> GetUserWitherror () {System.err.println ("le nom principal du thread est" + threint.CurrentThread (). GetName ()); tâche asynchrone. WebasyncTask <string> task3 = new WebaSyncTask <string> (10 * 1000l, () -> {System.err.println ("Le deuxième nom de thread est" + thread.currentThread (). GetName ()); // Exception lancée ici int num = 9/0; System.err.printLn (num); return "";}); // appelle cette méthode lorsque une exception est un exception. -> {System.err.println("==================================================================================== ==========================================================================================================. ==========================================================================================================. ===========================================================================================================. "========================================================================. ==========================================================================. ==========================================================================. ==========================================================================. ==========================================================================. ==========================================================================. ==========================================================================. ==========================================================================.La sortie de la console est la suivante:
Le nom du thread principal est http-nio-7000-exec-1
Task3 continue de gérer d'autres choses!
Le deuxième nom de thread est Mvcasync1
2018-06-15 09: 40: 13.538 Erreur 9168 --- [NIO-7000-EXEC-2] OACCC [. [. [.java.lang.arithmeticexception: / par zéro
sur com.example.demo.controller.getUserInfocontroller.lambda 5 $ (GetUserInfocontroller.java:93) ~ [Classes /: Na]
sur org.springframework.web.context.request.async.webasyncmanager.lambda $ startCallableProcesing 4 $ (webasyncmanager.java:317) ~ [printemps-web-5.0.6.release.jar: 5.0.6.release]
sur java.util.concurrent.executors $ runnableadapter.call (exécuteurs.java:511) ~ [na: 1.8.0_161]
sur java.util.concurrent.futuretask.run (futurask.java:266) ~ [na: 1.8.0_161]
sur java.lang.thread.run (thread.java:748) [na: 1.8.0_161]2018-06-15 09: 40: 13.539 Erreur 9168 --- [NIO-7000-EXEC-2] OACCC [. [. [. [DispatcherServlet]: servlet.service () pour servlet [DispatterServlet] dans le contexte avec PATH [/ Demo] Throw Exception [Demande de demande échoué; L'exception imbriquée est java.lang.arithmeticexception: / par zéro] avec une cause profonde
java.lang.arithmeticexception: / par zéro
sur com.example.demo.controller.getUserInfocontroller.lambda 5 $ (GetUserInfocontroller.java:93) ~ [Classes /: Na]
sur org.springframework.web.context.request.async.webasyncmanager.lambda $ startCallableProcesing 4 $ (webasyncmanager.java:317) ~ [printemps-web-5.0.6.release.jar: 5.0.6.release]
sur java.util.concurrent.executors $ runnableadapter.call (exécuteurs.java:511) ~ [na: 1.8.0_161]
sur java.util.concurrent.futuretask.run (futurask.java:266) ~ [na: 1.8.0_161]
sur java.lang.thread.run (thread.java:748) [na: 1.8.0_161]=================================================================================================.
La mission 3 s'est produite!
La tâche 3 est terminée!
Bien sûr, vous pouvez également faire des exceptions sur ce qui précède pour éviter les hostiles à l'opinion de l'utilisateur. Pour la gestion des exceptions, vous pouvez consulter un autre article dans mon article sur l'utilisation du schéma de gestion des erreurs de démarrage Spring Boot / Spring
Résultats de sortie du navigateur:
3. Tâche asynchrone du délai
Appel d'interface: http://localhost:7000/demo/getUserWithTimeOut.json
/ ** * Testez la tâche asynchrone dans laquelle la tâche a chronométré * @return * / @ requestmapping (value = "getuserwithtimeout.json", méthode = requestMethod.get) public webasyncTask <string> getuserWithTimeout () {System.err.println ("le nom du thread principal est" + thread.currentThread (). GetName ()); // Ceci est simulé pour démarrer une tâche asynchrone, délai de 10s webaSyncTask <string> tâche2 = new WebasyncTask <string> (10 * 1000l, () -> {System.err.println ("Le deuxième nom de thread est" + thread.currentThread (). GetName ()); // Tank Timeout appelle cette méthode task2.ontimeout (() -> { System.err.println("===================================================================================== ===========================================================================================================. ===========================================================================================================. ===========================================================================================================. "========================================================================. ==========================================================================. ==========================================================================. ==========================================================================. ==========================================================================. ==========================================================================. ==========================================================================. ==========================================================================.Résultats de l'exécution de la console:
Le nom du thread principal est http-nio-7000-exec-4
Task2 continue de gérer d'autres choses!
Le deuxième nom de thread est Mvcasync2
=======================================================================================================================.
La tâche 2 est terminée!
Résultats de l'exécution du navigateur:
4. Tâches asynchrones de la piscine de fil
Les tâches asynchrones dans les trois cas ci-dessus ne sont pas gérées par le mécanisme de pool de threads par défaut. C'est-à-dire que si une demande arrive, bien que le thread de traitement soit libéré, le système créera toujours un thread de tâche asynchrone pour chaque demande, qui est le thread de tâche asynchrone en commençant par MvcAsync comme nous l'avons vu ci-dessus. Autrement dit, cela ne fonctionnera pas, les frais généraux sont particulièrement élevés! Par conséquent, nous pouvons utiliser Thread Pool pour la gestion et passer directement une instance d'objet ThreadPoolTaskExecutor dans le constructeur de classe WebAsyncTask .
Voyons d'abord ce qui se passe lors de la réalisation de demandes simultanées dans le premier cas ci-dessus (ici, nous simulons les appels simultanés à http://localhost:7000/demo/getUserWithNoThing.json ):
La sortie de la console est la suivante:
Le premier nom de thread est Mvcasync57
Le premier nom de thread est Mvcasync58
Le premier nom de thread est Mvcasync59
Le premier nom de thread est Mvcasync60
Le premier nom de thread est Mvcasync61
Le premier nom de thread est Mvcasync62
Le premier nom de thread est Mvcasync63
Le premier nom de thread est Mvcasync64
Le premier nom de thread est Mvcasync65
Le premier nom de thread est Mvcasync66
Le premier nom de thread est Mvcasync67
Le premier nom de fil est Mvcasync68
Le premier nom de thread est Mvcasync69
Le premier nom de thread est Mvcasync70
Le premier nom de thread est Mvcasync71
Le premier nom de thread est Mvcasync72
Le premier nom de thread est Mvcasync73
Le premier nom de thread est Mvcasync74
Le premier nom de thread est Mvcasync76
Le premier nom de thread est Mvcasync75
Le premier nom de thread est Mvcasync77
Le premier nom de thread est Mvcasync78
Le premier nom de thread est Mvcasync79
Le premier nom de thread est Mvcasync80
Étant donné que le pool de threads n'est pas ajouté, 100 demandes ouvriront 100 threads de tâche asynchrones, ce qui est particulièrement coûteux et n'est pas recommandé.
Ce qui suit est la mise en œuvre du pool de threads:
Interface d'appel: http://localhost:7000/demo/getUserWithExecutor.json
/ ** * Test Thread Pool * @return * / @ requestmapping (value = "getuserwithexecutor.json", méthode = requestMethod.get) public webasynctask <string> getuserwithexecutor () {System.err.println ("le nom du thread principal est" + thread.currentThread (). GetName ()); // Ceci est simulé pour démarrer une tâche asynchrone, et un pool de fils est passé ici. WebaSyncTask <string> task1 = new WebaSyncTask <string> (10 * 1000l, exécuteur testamentaire, () -> {System.err.println ("Le premier nom de thread est" + thread.currentThread (). GetName ()); Thread.sleep (5000l); return "Task 4 exécute avec succès! Aucune exception n'a été thrown!";}); // Appelez cette méthode lorsque l'exécution de la tâche est terminée tâche1.oncompletion (() -> {System.err.println ("Task 4 exécute terminée!");}); System.err.println ("Task4 continue de gérer d'autres choses!"); Retour tâche1;}Le pool de fils est défini comme suit:
@ConfigurationPublic class MyExecutor {@bean public static threadpooltaskexecutor getExecutor () {ThreadpoolTasKexecutor taskexecutor = new ThreadpoolTasKExEcutor (); taskexecutor.setCorepoolSize (30); taskexecutor.setMaxPoolSize (30); taskexecutor.setQueueCapacity (50); taskexecutor.setThreadnamePrefix ("Huang"); // Le nom de thread de tâche asynchrone est le préfixe Huang RETOUR TASKEXECUTOR; }}Des tests simultanés ci-dessus peuvent être utilisés pour obtenir les résultats suivants:
L'exemple d'adresse de code de cet article: https://github.com/smallercoder/webasynctask
L'utilisation de pools de threads peut enregistrer les ressources du serveur et optimiser les capacités de traitement du serveur. N'oubliez pas de les utiliser fréquemment! Merci d'avoir lu! Si vous pensez que cela vous sera utile, veuillez commencer!
Ce qui précède est tout le contenu de cet article. J'espère que cela sera utile à l'apprentissage de tous et j'espère que tout le monde soutiendra davantage Wulin.com.