Maison > Java > javaDidacticiel > Comment utiliser le multithread avec élégance dans SpringBoot

Comment utiliser le multithread avec élégance dans SpringBoot

王林
Libérer: 2023-05-11 15:31:06
avant
1624 Les gens l'ont consulté

Utilisation rapide

L'annotation @EnableAsync doit être ajoutée à l'application SpringBoot pour activer les appels asynchrones. Généralement, un pool de threads est configuré et la méthode asynchrone est transmise à un pool de threads spécifique pour être complétée, comme suit :

@Configuration
@EnableAsync
public class AsyncConfiguration {
 
    @Bean("doSomethingExecutor")
    public Executor doSomethingExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 核心线程数:线程池创建时候初始化的线程数
        executor.setCorePoolSize(10);
        // 最大线程数:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
        executor.setMaxPoolSize(20);
        // 缓冲队列:用来缓冲执行任务的队列
        executor.setQueueCapacity(500);
        // 允许线程的空闲时间60秒:当超过了核心线程之外的线程在空闲时间到达之后会被销毁
        executor.setKeepAliveSeconds(60);
        // 线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池
        executor.setThreadNamePrefix("do-something-");
        // 缓冲队列满了之后的拒绝策略:由调用线程处理(一般是主线程)
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
        executor.initialize();
        return executor;
    }
 
}
Copier après la connexion
.

La méthode d'utilisation est très simple. Ajoutez l'annotation @Async aux méthodes qui nécessitent des méthodes asynchrones

@RestController
public class AsyncController {
 
    @Autowired
    private AsyncService asyncService;
 
    @GetMapping("/open/something")
    public String something() {
        int count = 10;
        for (int i = 0; i < count; i++) {
            asyncService.doSomething("index = " + i);
        }
        return "success";
    }
}
 
 
@Slf4j
@Service
public class AsyncService {
 
    // 指定使用beanname为doSomethingExecutor的线程池
    @Async("doSomethingExecutor")
    public String doSomething(String message) {
        log.info("do something, message={}", message);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            log.error("do something error: ", e);
        }
        return message;
    }
}
Copier après la connexion

Accès : 127.0.0.1:8080/open/something, le journal est le suivant

06/02/2023 23:42 :42.486 INFO 21168 --- [io-8200-exec -17] x.g.b.system.controller.AsyncController : faire quelque chose se termine, durée 8 millisecondes
2023-02-06 23:42:42.488 INFO 21168 --- [ faire quelque chose -1] x.gits.boot.system.service. AsyncService : faire quelque chose, message=index = 0
2023-02-06 23:42:42.488 INFO 21168 --- [ do-something-5] x.gits. boot.system.service.AsyncService : faire quelque chose, message= index = 4
2023-02-06 23:42:42.488 INFO 21168 --- [ do-something-4] x.gits.boot.system.service.AsyncService : faire quelque chose, message=index = 3
2023-02 -06 23:42:42.488 INFO 21168 --- [ do-something-6] x.gits.boot.system.service.AsyncService : faire quelque chose, message=index = 5
2023-02-06 23:42:42.488 INFO 21168 --- [ do-something-9] x.gits.boot.system.service.AsyncService : faire quelque chose, message=index = 8
2023-02- 06 23:42:42.488 INFO 21168 --- [ do -something-8] x.gits.boot.system.service.AsyncService : faire quelque chose, message=index = 7
2023-02-06 23:42:42.488 INFO 21168 --- [do-something-10] x. gits.boot.system.service.AsyncService : faire quelque chose, message=index = 9
2023-02-06 23:42:42.488 INFO 21168 --- [ faire- quelque chose-7] x.gits.boot.system.service .AsyncService : faire quelque chose, message=index = 6
2023-02-06 23:42:42.488 INFO 21168 --- [ faire-quelque chose-2] x.gits .boot.system.service.AsyncService : faire quelque chose, message =index = 1
2023-02-06 23:42:42.488 INFO 21168 --- [ do-something-3] x.gits.boot.system.service. AsyncService : faire quelque chose, message=index = 2

On peut voir que l'effet de l'exécution asynchrone a été obtenu et que le pool de threads que nous avons configuré a été utilisé.

Obtenir la valeur de retour de la méthode asynchrone

Lorsque la méthode asynchrone a une valeur de retour, comment obtenir le résultat de retour de l'exécution de la méthode asynchrone ? À ce stade, la méthode qui doit être appelée de manière asynchrone a la valeur de retour CompletableFuture.

CompletableFuture est une amélioration de Feature. Feature ne peut gérer que des tâches asynchrones simples, tandis que CompletableFuture peut effectuer des combinaisons complexes de plusieurs tâches asynchrones. Comme suit :

@RestController
public class AsyncController {
 
    @Autowired
    private AsyncService asyncService;
 
    @SneakyThrows
    @ApiOperation("异步 有返回值")
    @GetMapping("/open/somethings")
    public String somethings() {
        CompletableFuture<String> createOrder = asyncService.doSomething1("create order");
        CompletableFuture<String> reduceAccount = asyncService.doSomething2("reduce account");
        CompletableFuture<String> saveLog = asyncService.doSomething3("save log");
 
        // 等待所有任务都执行完
        CompletableFuture.allOf(createOrder, reduceAccount, saveLog).join();
        // 获取每个任务的返回结果
        String result = createOrder.get() + reduceAccount.get() + saveLog.get();
        return result;
    }
}
 
 
@Slf4j
@Service
public class AsyncService {
 
    @Async("doSomethingExecutor")
    public CompletableFuture<String> doSomething1(String message) throws InterruptedException {
        log.info("do something1: {}", message);
        Thread.sleep(1000);
        return CompletableFuture.completedFuture("do something1: " + message);
    }
 
    @Async("doSomethingExecutor")
    public CompletableFuture<String> doSomething2(String message) throws InterruptedException {
        log.info("do something2: {}", message);
        Thread.sleep(1000);
        return CompletableFuture.completedFuture("; do something2: " + message);
    }
 
    @Async("doSomethingExecutor")
    public CompletableFuture<String> doSomething3(String message) throws InterruptedException {
        log.info("do something3: {}", message);
        Thread.sleep(1000);
        return CompletableFuture.completedFuture("; do something3: " + message);
    }
}
Copier après la connexion

Interface d'accès

C:UsersAdministrator>curl -X GET "http://localhost:8080/open/something" -H "accepter : */*"
faire quelque chose1 : créer une commande ;
faire quelque chose2 : réduire le compte ;
faire quelque chose3 : enregistrer le journal

Les journaux de touches sur la console sont les suivants :

2023-02-06 00:27:42.238 INFO 5672 --- [ do-something-3] x .gits.boot .system.service.AsyncService : faire quelque chose3 : enregistrer le journal
2023-02-06 00:27:42.238 INFO 5672 --- [do-something-2] x.gits.boot.system.service.AsyncService : faire quelque chose2 : réduire le compte
2023-02-06 00:27:42.238 INFO 5672 --- [ do-something-1] x.gits.boot.system.service.AsyncService : faire quelque chose1 : créer une commande

Notes

@ Les annotations Async échoueront dans les scénarios suivants, ce qui signifie que l'annotation @Async est clairement utilisée, mais que le multithreading n'est pas utilisé.

  • Les méthodes asynchrones sont modifiées avec le mot-clé static ;

  • La classe asynchrone n'est pas un bean du conteneur Spring (généralement annoté @Component et @Service, et peut être analysée par Spring) ; disponible dans les applications SpringBoot Ajoutez l'annotation @EnableAsync ;

  • Dans la même classe, si une méthode appelle une autre méthode avec une annotation @Async, l'annotation ne prendra pas effet. La raison en est que la méthode annotée avec @Async est exécutée dans la classe proxy.

  • Il est à noter que : la valeur de retour d'une méthode asynchrone utilisant l'annotation @Async ne peut être que void ou Future et ses sous-classes. Lorsque le résultat renvoyé est d'un autre type, la méthode sera toujours exécutée de manière asynchrone, mais le. la valeur de retour sera nulle. Une partie du code source est la suivante :

  • AsyncExecutionInterceptor#invoke

Grâce aux exemples ci-dessus, @Async est en fait exécuté de manière asynchrone via Future ou CompletableFuture, et Spring l'encapsule pour le rendre plus pratique. pour que nous puissions l'utiliser.

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!

Étiquettes associées:
source:yisu.com
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal