并发编程线程池以及 @Async 注解的使用

简介: 并发编程线程池以及 @Async 注解的使用

建议先看我另外一篇文章:并发编程使用了 线程池 ThreadPoolExecutor 程序性能有了质的突破

开发环境
  • SpringBoot 2.1.10.RELEASE
  • JDK 1.8
1:启动类添加@EnableAsync注解
package com.nobody;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;

@SpringBootApplication
@EnableAsync
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}
2:线程池配置
package com.nobody.config;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

@Configuration
public class ExecutorConfig {

    public static final int CORE_POOL_SIZE = 5;

    public static final int MAX_POOL_SIZE = 10;

    public static final int QUEUE_CAPACITY = 100;

    @Bean("myExecutor")
    public Executor asyncServiceExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 核心线程数大小
        executor.setCorePoolSize(CORE_POOL_SIZE);
        // 最大线程数大小
        executor.setMaxPoolSize(MAX_POOL_SIZE);
        // 阻塞队列容量
        executor.setQueueCapacity(QUEUE_CAPACITY);
        // 线程名前缀
        executor.setThreadNamePrefix("myTask-");
        // rejectionPolicy:当queue达到maxSize并且此时maxPoolSize也达到最大值的时候,对于新任务的处理策略
        // CallerRunsPolicy:不在新线程中执行任务,而是交由调用者所在的线程来执行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }
}
3:编写异步方法
package com.nobody.domain;

import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;

@Service
public class AsyncService {

    private static final Logger LOGGER = LoggerFactory.getLogger(AsyncService.class);

    // 简单版本
    @Async
    public void asyncTaskA() {
        LOGGER.info("asyncTaskA 异步方法执行.");
    }

    // 入参类型,此处将调用者(线程)的MDC信息传入,主要是保持日志输出时,两个线程有同样的traceId
    @Async
    public void asyncTaslB(Map<String, String> contextMap) {
        MDC.setContextMap(contextMap);
        LOGGER.info("asyncTaskB 异步方法执行.");
    }

    // 线程执行后计数器减1
    @Async
    public void asyncTaskC(CountDownLatch cdl) {
        LOGGER.info("asyncTaskC 异步方法执行.");
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        cdl.countDown();
    }

    // 有返回参数类型
    @Async
    public Future<String> asyncTaskD(String message) {
        LOGGER.info("asyncTaskD 异步方法执行.");
        return new AsyncResult<String>("@" + message);
    }

}
4:异步调用
package com.nobody.controller;

import java.util.concurrent.ExecutionException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.nobody.domain.AsyncService;

@RestController
@RequestMapping("demo")
public class DemoController {

    private static final Logger LOGGER = LoggerFactory.getLogger(DemoController.class);

    @Autowired
    private AsyncService asyncService;

    @GetMapping("test")
    public void test() throws InterruptedException, ExecutionException {

        asyncService.asyncTaskA();

        LOGGER.info("主线程执行...");

    }

}

输出结果:
在这里插入图片描述

package com.nobody.controller;

import java.util.UUID;
import java.util.concurrent.ExecutionException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.nobody.domain.AsyncService;

@RestController
@RequestMapping("demo")
public class DemoController {

    private static final Logger LOGGER = LoggerFactory.getLogger(DemoController.class);

    @Autowired
    private AsyncService asyncService;

    @GetMapping("test")
    public void test() throws InterruptedException, ExecutionException {

        MDC.put("traceId", UUID.randomUUID().toString().replaceFirst("-", ""));
        asyncService.asyncTaskB(MDC.getCopyOfContextMap());

        LOGGER.info("主线程执行...");

    }

}

输出结果:
在这里插入图片描述

package com.nobody.controller;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.nobody.domain.AsyncService;

@RestController
@RequestMapping("demo")
public class DemoController {

    private static final Logger LOGGER = LoggerFactory.getLogger(DemoController.class);

    @Autowired
    private AsyncService asyncService;

    @GetMapping("test")
    public void test() throws InterruptedException, ExecutionException {

        CountDownLatch cdl = new CountDownLatch(2);
        asyncService.asyncTaskC(cdl);
        asyncService.asyncTaskC(cdl);
        try {
            // 等等两个线程执行后,再继续下面的执行,如果超过5s则不等待
            cdl.await(5, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        LOGGER.info("主线程执行...");

    }

}

输出结果:
在这里插入图片描述

package com.nobody.controller;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.nobody.domain.AsyncService;

@RestController
@RequestMapping("demo")
public class DemoController {

    private static final Logger LOGGER = LoggerFactory.getLogger(DemoController.class);

    @Autowired
    private AsyncService asyncService;

    @GetMapping("test")
    public void test() throws InterruptedException, ExecutionException {

        Future<String> future = asyncService.asyncTaskD("Mr.nobody");
        LOGGER.info("future result:" + future.get());

        LOGGER.info("主线程执行...");

    }

}

在这里插入图片描述

相关文章
|
26天前
|
Java 程序员 调度
【JAVA 并发秘籍】进程、线程、协程:揭秘并发编程的终极武器!
【8月更文挑战第25天】本文以问答形式深入探讨了并发编程中的核心概念——进程、线程与协程,并详细介绍了它们在Java中的应用。文章不仅解释了每个概念的基本原理及其差异,还提供了实用的示例代码,帮助读者理解如何在Java环境中实现这些并发机制。无论你是希望提高编程技能的专业开发者,还是准备技术面试的求职者,都能从本文获得有价值的见解。
33 1
|
1月前
|
Java 开发者
解锁并发编程新姿势!深度揭秘AQS独占锁&ReentrantLock重入锁奥秘,Condition条件变量让你玩转线程协作,秒变并发大神!
【8月更文挑战第4天】AQS是Java并发编程的核心框架,为锁和同步器提供基础结构。ReentrantLock基于AQS实现可重入互斥锁,比`synchronized`更灵活,支持可中断锁获取及超时控制。通过维护计数器实现锁的重入性。Condition接口允许ReentrantLock创建多个条件变量,支持细粒度线程协作,超越了传统`wait`/`notify`机制,助力开发者构建高效可靠的并发应用。
72 0
|
9天前
|
缓存 监控 Java
Java中的并发编程:理解并应用线程池
在Java的并发编程中,线程池是提高应用程序性能的关键工具。本文将深入探讨如何有效利用线程池来管理资源、提升效率和简化代码结构。我们将从基础概念出发,逐步介绍线程池的配置、使用场景以及最佳实践,帮助开发者更好地掌握并发编程的核心技巧。
|
17天前
|
Java Spring
运行@Async注解的方法的线程池
自定义@Async注解线程池
41 3
|
30天前
|
数据采集 Java Python
Python并发编程:多线程(threading模块)
Python是一门强大的编程语言,提供了多种并发编程方式,其中多线程是非常重要的一种。本文将详细介绍Python的threading模块,包括其基本用法、线程同步、线程池等,最后附上一个综合详细的例子并输出运行结果。
|
28天前
|
数据采集 Java Python
Python并发编程:多线程(threading模块)
本文详细介绍了Python的threading模块,包括线程的创建、线程同步、线程池的使用,并通过多个示例展示了如何在实际项目中应用这些技术。通过学习这些内容,您应该能够熟练掌握Python中的多线程编程,提高编写并发程序的能力。 多线程编程可以显著提高程序的并发性能,但也带来了新的挑战和问题。在使用多线程时,需要注意避免死锁、限制共享资源的访问,并尽量使用线程池来管理和控制线程。
|
1月前
|
缓存 Java 数据处理
Java中的并发编程:解锁多线程的力量
在Java的世界里,并发编程是提升应用性能和响应能力的关键。本文将深入探讨Java的多线程机制,从基础概念到高级特性,逐步揭示如何有效利用并发来处理复杂任务。我们将一起探索线程的创建、同步、通信以及Java并发库中的工具类,带你领略并发编程的魅力。
|
19天前
|
Java 数据库连接 微服务
揭秘微服务架构下的数据魔方:Hibernate如何玩转分布式持久化,实现秒级响应的秘密武器?
【8月更文挑战第31天】微服务架构通过将系统拆分成独立服务,提升了可维护性和扩展性,但也带来了数据一致性和事务管理等挑战。Hibernate 作为强大的 ORM 工具,在微服务中发挥关键作用,通过二级缓存和分布式事务支持,简化了对象关系映射,并提供了有效的持久化策略。其二级缓存机制减少数据库访问,提升性能;支持 JTA 保证跨服务事务一致性;乐观锁机制解决并发数据冲突。合理配置 Hibernate 可助力构建高效稳定的分布式系统。
36 0
|
20天前
|
程序员 调度 C++
解锁Ruby并发编程新境界!Fiber与线程:轻量级VS重量级,你选哪一派引领未来?
【8月更文挑战第31天】Ruby提供了多种并发编程方案,其中Fiber与线程是关键机制。Fiber是自1.9版起引入的轻量级并发模型,无需独立堆栈和上下文切换,由程序员控制调度。线程则为操作系统级别,具备独立堆栈和上下文,能利用多核处理器并行执行。通过示例代码展示了Fiber和线程的应用场景,如任务调度和多URL数据下载,帮助开发者根据需求选择合适的并发模型,提升程序性能与响应速度。
25 0
|
1月前
|
Java API 开发者
Java中的并发编程:解锁多线程的潜力
在数字化时代的浪潮中,并发编程已成为软件开发的核心技能之一。本文将深入探讨Java中的并发编程概念,通过实例分析与原理解释,揭示如何利用多线程提升应用性能和响应性。我们将从基础的线程创建开始,逐步过渡到高级的同步机制,并探讨如何避免常见的并发陷阱。读者将获得构建高效、稳定并发应用所需的知识,同时激发对Java并发更深层次探索的兴趣。
33 2