使用ThreadPoolTaskExecutor与@Async快速实现多线程异步 *** 作

使用ThreadPoolTaskExecutor与@Async快速实现多线程异步 *** 作,第1张

使用ThreadPoolTaskExecutor与@Async快速实现多线程异步 *** 作 前言

ThreadpoolTaskExecutor相对于ThreadpoolExecutor来说,是使用了ThreadPoolExecutor并增强,扩展了更多特性。它是Spring提供的线程池,帮助我们快速创建一个可用的线程池来使用。

@Async是Spring的注解,可以加在类或方法上。通俗的来讲,如果加上了这个注解,那么该类或者该方法在使用时将会进行异步处理,也就是创建一个线程来实现这个类或者方法,实现多线程。

使用

1、配置线程池

package com.czf.connect.config;

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

import java.util.concurrent.ThreadPoolExecutor;


@EnableAsync	//表示开启多线程
@Configuration
public class ThreadPoolConfig {
    
    private static final int CORE_POOL_SIZE = 20;
    
    private static final int MAX_POOL_SIZE = 40;
    
    private static final int QUEUE_CAPACITY = 200;
    
    private static final int KEEP_ALIVE_SEConDS = 60;

    @Bean(name = "threadPoolTaskExecutor")	//ThreadPoolTaskExecutor不会自动创建ThreadPoolExecutor,需要手动调initialize才会创建。如果@Bean就不需手动,会自动InitializingBean的afterPropertiesSet来调initialize
    public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 设置线程池最大线程数
        executor.setMaxPoolSize(MAX_POOL_SIZE);
        // 线程池活跃的线程数
        executor.setCorePoolSize(CORE_POOL_SIZE);
        // 设置线程队列最大线程数
        executor.setQueueCapacity(QUEUE_CAPACITY);
        // 线程池维护线程所允许的空闲时间
        executor.setKeepAliveSeconds(KEEP_ALIVE_SECONDS);
        executor.setThreadNamePrefix("task-async");//线程前缀名称
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return executor;
    }
}

2、需要异步 *** 作的方法或类:

@Slf4j
@Component		//将该类注入到容器中
public class AsyncTest {
    @Async("threadPoolTaskExecutor")		//调用该线程池
    public void task() throws InterruptedException {
        Thread.sleep(4000);
        log.info("task异步处理");
    }
}

3、测试类

@Slf4j
@RestController
public class PoolTest {

    @Autowired
    private AsyncTest asyncTest;

    @RequestMapping("/pool")
    public void poolTest() throws InterruptedException {
        log.info("主线程开始");
        asyncTest.task();
        log.info("主线程结束");
    }
}

4、结果:

可以看出是由不同的线程执行。

注意要点

1、@Async需要在Spring环境下才能启动,使用的是AOP动态代理技术

2、@Async使用的是动态代理来实现异步调用,因此不能够在同一个类中进行调用。方法一定要从另一个类中调用,也就是从类的外部调用,类的内部调用是无效的,有可能因为调用方法的是对象本身而不是代理对象,因为没有经过Spring容器。

3、注解的方法必须是public方法

4、需要在@SpringBootApplication启动类或者@configure注解类上 添加注解@EnableAsync启动多线程注解。

5、@Async就会对标注的方法开启异步多线程调用,注意,这个方法的类一定要交给spring容器来管理。

6、异步方法使用注解@Async的返回值只能为void或者Future。

有返回值的异步处理

上述方法实现的是无返回值的异步 *** 作,接下来实现的是有返回值的异步 *** 作,即返回值为Future。

异步方法

    @Async("threadPoolTaskExecutor")
    public Future task1() throws InterruptedException {
        log.info("异步处理开始");
        Thread.sleep(2000);
        return new AsyncResult("异步处理");
    }
    
    @Async("threadPoolTaskExecutor")
    public Future task2() throws InterruptedException {
        log.info("异步处理开始");
        User2 user2 = new User2();
        user2.setName("zhangsan");
        user2.setId(1);
        Thread.sleep(2000);
        return new AsyncResult(user2);
    }

接口实现

    @RequestMapping("/pool1")
    public String poolTest1() throws InterruptedException, ExecutionException {
        log.info("主线程开始");
        Future stringFuture = asyncTest.task1();
        log.info("主线程结束");
        Thread.sleep(2000);
        log.info("{}",stringFuture.get());
        return stringFuture.get();
    }

    @RequestMapping("/pool2")
    public User2 poolTest2() throws InterruptedException, ExecutionException {
        log.info("主线程开始");
        Future stringFuture = asyncTest.task2();
        log.info("主线程结束");
        Thread.sleep(2000);
        log.info("{}",stringFuture.get());
        return stringFuture.get();
    }

poolTest1方法:

poolTest2方法:

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5706908.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存