Hoje vamos aprender a realizar programação assíncrona na primavera. Todos sabemos que os threads que o servidor da web processam request de solicitações são obtidas no pool de threads, o que não é difícil de explicar, porque quando o número de solicitações da Web é muito grande, como criar um tópico de processamento quando uma solicitação entra. Desde que a sobrecarga da criação de threads e a troca de contexto de threads é relativamente grande, o servidor da Web enfrentará uma falha. Além disso, os threads de processamento criados pelo servidor da Web são executados de maneira síncrona do começo ao fim por padrão. Ou seja, se o processamento do encadeamento A for responsável pelo processamento da solicitação B, quando B não return , o processamento do thread a não pode escapar para processar outras solicitações, o que limitará bastante o recurso de processamento simultâneo do servidor da Web.
Portanto, o pool de threads resolve o problema da reciclagem de threads, então como resolver a solicitação de processamento síncrono? A resposta é processamento assíncrono. O que é processamento assíncrono? O processamento assíncrono permite que a solicitação B acima esteja ociosa antes que o processamento da solicitação acima seja concluído, e o encadeamento A pode ser libertado para continuar processando outras solicitações. Em seguida, podemos fazer isso, reiniciar o encadeamento C dentro do encadeamento A para executar a tarefa, deixar um retorno diretamente ao servidor da Web e continuar aceitando novas solicitações.
Antes de iniciar a explicação abaixo, primeiro distinguirei dois conceitos aqui:
1. Trevas de processo
O tópico de processamento pertence ao servidor da web, é responsável pelo processamento de solicitações de usuário e é gerenciado pelo pool de threads
2. Trebo assíncrono
Os threads assíncronos são threads definidos pelo usuário e podem ser gerenciados por pools de threads.
A Spring fornece suporte para tarefas assíncronas. Tarefas assíncronas podem ser implementadas usando a classe WebAsyncTask . Ao mesmo tempo, também podemos definir o processamento correspondente de retorno de chamada para tarefas assíncronas, como como lidar quando a tarefa cronometrou e como fazer uma exceção. Tarefas assíncronas geralmente são muito práticas. Por exemplo, queremos deixar uma operação que possa ser processada por um longo tempo para o encadeamento assíncrono processar ou quando um pedido é pago, permitimos que a tarefa assíncrona consulte o resultado do pagamento do pedido.
1. Tarefas assíncronas normais
Para conveniência de demonstração, a execução de tarefas assíncronas é simulada usando Thread.sleep(long) . Agora suponha que o usuário solicite a seguinte interface:
http://localhost:7000/demo/getUserWithNoThing.json
A interface de tarefa assíncrona é definida da seguinte forma:
/*** Teste tarefas assíncronas sem nenhuma exceção*/@requestMapp (value = "getUserwithnothing.json", método = requestmethod.get) public webasynctask <string> getUserwithNothing () {// Print Processing Thread Name System.err.println ("o nome principal é" Thread Is " // Isso simula a abertura de uma tarefa assíncrona, com um tempo limite do 10S WebAsyncTask <String> tarefa1 = novo webAsyncTask <String> (10 * 1000l, () -> {System.err.println ("O primeiro nome do thread é" + ThreadhrentThread (). 1000L); // O método é chamado quando a execução da tarefa é concluída Task1.Oncompletion (() -> {System.err.println ("Tarefa 1 executa concluído!");}); System.err.println ("Task1 continua a lidar com outras coisas!"); Retornar tarefa1;}O console impressa da seguinte maneira:
O nome do tópico principal é HTTP-NIO-7000-EXEC-1
Task1 continua lidando com outras coisas!
O primeiro nome do tópico é mvCasync1
Tarefa 1 foi concluída!
Os resultados do navegador são os seguintes:
2. Exceder a tarefa assíncrona de exceção
Chamada de interface: http://localhost:7000/demo/getUserWithError.json
/*** Teste a tarefa assíncrona em que ocorre um erro* @return*/ @requestMapp (value = "getUserwitherror.json", método = requestmethod.get) public webasyncTask <sth) getUserwitherror () {System.err.println ("o nome principal é" +.s; tarefa assíncrona. WebAsyncTask <String> task3 = novo webAsyncTask <String> (10 * 1000l, () -> {System.err.println ("o nome do segundo thread é" + thread.currentThread (). Task3.ONERROR (() -> {System.err.println("==================================================================================== ========================================================================================================= ========================================================================================================= ========================================================================================================== "=============================================================== ================================================================== ================================================================== ================================================================== ================================================================== ================================================================== ================================================================== ==================================================================A saída do console é a seguinte:
O nome do tópico principal é HTTP-NIO-7000-EXEC-1
Task3 continua a lidar com outras coisas!
O segundo nome do thread é mvCasync1
2018-06-15 09: 40: 13.538 Erro 9168 --- [NIO-7000-EXEC-2] OACCC [. [. [.java.lang.arithmeticexception: / por zero
em com.example.demo.controller.getUserinfocontroller.lambda $ 5 (getUserinfocontroller.java:93) ~ [Classes/: Na]
em org.springframework.web.context.request.async.webasyncmanager.lambda $ startCallableProcessing $ 4 (webasyncmanager.java:317) ~ [spring-web-5.0.6.release.Jar: 5.0.6.rease]
em java.util.concurrent.executores $ runnableAdapter.call (executores.java:511) ~ [na: 1.8.0_161]
em java.util.concurrent.futureTask.run (futureTask.java:266) ~ [na: 1.8.0_161]
em java.lang.thread.run (thread.java:748) [NA: 1.8.0_161]2018-06-15 09: 40: 13.539 Erro 9168 --- [NIO-7000-EXEC-2] OACCC [. [. [. Exceção aninhada é java.lang.arithmeticexception: / por zero] com causa raiz
java.lang.arithmeticexception: / por zero
em com.example.demo.controller.getUserinfocontroller.lambda $ 5 (getUserinfocontroller.java:93) ~ [Classes/: Na]
em org.springframework.web.context.request.async.webasyncmanager.lambda $ startCallableProcessing $ 4 (webasyncmanager.java:317) ~ [spring-web-5.0.6.release.Jar: 5.0.6.rease]
em java.util.concurrent.executores $ runnableAdapter.call (executores.java:511) ~ [na: 1.8.0_161]
em java.util.concurrent.futureTask.run (futureTask.java:266) ~ [na: 1.8.0_161]
em java.lang.thread.run (thread.java:748) [NA: 1.8.0_161]==============================================================================================================================
Missão 3 ocorreu!
Tarefa 3 foi concluída!
Obviamente, você também pode lidar com o manuseio de exceção acima para evitar hostis na opinião do usuário. Para manuseio de exceções, você pode conferir outro artigo no meu artigo sobre o uso do esquema de manuseio de erro unificado da Spring Boot/Spring
Resultados da saída do navegador:
3. Tarefa de tempo limite assíncrono
Chamada de interface: http://localhost:7000/demo/getUserWithTimeOut.json
/*** Teste a tarefa assíncrona na qual a tarefa cronometrou* @return*/ @requestMapp (value = "getUserwithtimeout.json", métod = requestmethod.get) public webasyncTask <string> getUserwithtimeout () {System.err.println ("o nome principal do thread Is" // Isso é simulado para iniciar uma tarefa assíncrona, tempo limite do 10S WebAsyncTask <String> task2 = novo webAsyncTask <String> (10 * 1000l, () -> {System.err.println ("o nome do thread é" + Thread.CurrentThread (). GetName ()); }); // Tempo limite da tarefa chama essa tarefa de método2.Ontimeout (() -> { System.err.println ("==============================================================================================================================================================================================================================eó====roeroóSeeóroerorororororororororororoat pela Bed ========================================================================================================== ========================================================================================================== ========================================================================================================== "=============================================================== ================================================================== ================================================================== ================================================================== ================================================================== ================================================================== ================================================================== ==================================================================Resultados de execução do console:
O nome do tópico principal é http-nio-7000-exeC-4
Task2 continua a lidar com outras coisas!
O segundo nome do tópico é mvCasync2
==================================================================================================
Tarefa 2 foi concluída!
Resultados de execução do navegador:
4. Tarefas assíncronas do pool de threads
As tarefas assíncronas nos três casos acima não são gerenciadas pelo mecanismo do pool de threads por padrão. Ou seja, se uma solicitação entrar, embora o thread de processamento seja liberado, o sistema ainda criará um encadeamento de tarefa assíncrono para cada solicitação, que é o thread de tarefa assíncrono que começa com MvcAsync como vimos acima. Ou seja, isso não funciona, a sobrecarga é particularmente alta! Portanto, podemos usar o pool de threads para gerenciamento e passar diretamente uma instância do objeto ThreadPoolTaskExecutor no construtor da classe WebAsyncTask .
Vamos primeiro olhar o que acontece ao realizar solicitações simultâneas no primeiro caso acima (aqui simulamos chamadas simultâneas para http://localhost:7000/demo/getUserWithNoThing.json ):
A saída do console é a seguinte:
O primeiro nome do tópico é MVCasync57
O primeiro nome do tópico é MVCasync58
O primeiro nome do tópico é MVCASYNC59
O primeiro nome do tópico é mvCasync60
O primeiro nome do tópico é mvCasync61
O primeiro nome do tópico é mvCasync62
O primeiro nome do tópico é mvCasync63
O primeiro nome do tópico é MVCasync64
O primeiro nome do tópico é mvCasync65
O primeiro nome do tópico é MVCasync66
O primeiro nome do tópico é mvCasync67
O primeiro nome do tópico é MVCasync68
O primeiro nome do tópico é mvCasync69
O primeiro nome do tópico é MVCasync70
O primeiro nome do tópico é mvCasync71
O primeiro nome do tópico é mvCasync72
O primeiro nome do tópico é mvCasync73
O primeiro nome do tópico é MVCasync74
O primeiro nome do tópico é MVCasync76
O primeiro nome do tópico é mvCasync75
O primeiro nome do tópico é mvCasync77
O primeiro nome do tópico é MVCasync78
O primeiro nome do tópico é MVCasync79
O primeiro nome do tópico é mvCasync80
Como o pool de threads não é adicionado, 100 solicitações abrirão 100 threads de tarefas assíncronos, o que é particularmente caro e não é recomendado.
A seguir, a implementação do pool de threads:
Interface de chamada: http://localhost:7000/demo/getUserWithExecutor.json
/*** Pool de threads de teste* @return*/ @requestMapp (value = "getUserwithExecutor.json", métod = requestMethod.get) public webAsyncTask <string> getUserwithExecutor () {System.err.println ("o nome do thread principal é" +.CurrentTheRead (). // Isso é simulado para iniciar uma tarefa assíncrona, e um pool de threads é passado aqui. WebAsyncTask <String> tarefa1 = novo webAsyncTask <String> (10 * 1000l, executor, () -> {System.err.println ("O primeiro nome do thread é" + thread.currentThread (). // Ligue para este método quando a execução da tarefa for concluída Task1.Oncompletion (() -> {System.err.println ("Tarefa 4 executa concluída!");}); System.err.println ("Task4 continua a lidar com outras coisas!"); Retornar tarefa1;}O pool de threads é definido da seguinte maneira:
@ConfigurationPublic Classe MyExecutor {@Bean Public Static ThreadPooltaskexecutor getExecutor () {threadpooltaskexecutor taskexecutor = new ThreadPooltaskexecutor (); taskexecutor.setCorePoolSize (30); taskexecutor.setMaxPoolSize (30); taskexecutor.setQueuecapacity (50); taskexecutor.setThreadNamePrefix ("huang"); // o nome do thread de tarefas assíncronas é o prefixo Huang Return taskexecutor; }}Testes simultâneos acima podem ser usados para obter os seguintes resultados:
O endereço do código de amostra deste artigo: https://github.com/smalmercoder/webasynctask
O uso de pools de threads pode salvar os recursos do servidor e otimizar os recursos de processamento do servidor. Lembre -se de usá -los com frequência! Obrigado pela leitura! Se você acha que será útil para você, comece!
O exposto acima é todo o conteúdo deste artigo. Espero que seja útil para o aprendizado de todos e espero que todos apoiem mais o wulin.com.