心里有爱眼里有光

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  3 随笔 :: 0 文章 :: 0 评论 :: 2356 阅读
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

   大多数时候处理业务都是以同步的方式来实现的。但在有些特殊的场景中,需要用异步的方式来实现。

  1、最原始的实现异步的方式:单独起一个线程。缺点在于:异步处理业务太多时,同时运行的线程太多,可能导致服务器崩溃。

  2、然后,出现了线程池,线程池对线程数量进行控制和对线程进行复用,解决了上面的问题。

  3、在2中,程序员需要自己编写一个线程,然后交给线程池管理。spring为了简化程序员的代码,内置了@Async注解,程序员只需编写纯业务代码和设置自己的线程池即可。

       基于@Async标注的⽅法,称之为异步⽅法;这些⽅法将在执⾏的时候,将会在独⽴的线程中被执⾏,调⽤者⽆需等待它的完成,即可继续其他的操作。

 

如何使用:

  1、在应用中用@EnableAsync注解来启用@Aysnc注解。可以在spring⼊⼝类加,也可以在需要调⽤异步⽅法的类上加,也可以在应用配置类上加。

  

 

 

   2、在需要异步的方法上加@Aysnc。如果加在类上,相当于这个类的所有方法都加了@Aysnc,那么这个类所有的⽅法都是异步执⾏的。

复制代码
public class AysncTask {

    /**
     * taskA()被调用时,该方法会被异步执行:会将任务交给线程池去完成
     */
    @Async
    public void taskA() {
        System.out.println("AAAAAAAA");
    }
    
    public void taskB() {
        System.out.println("BBBBBBBBBBB");
    }
}
复制代码
复制代码
@Async
public class AysncTask {

    /**
     * taskA()被调用时,该方法会被异步执行:会将任务交给线程池去完成
     */
    public void taskA() {
        System.out.println("AAAAAAAA");
    }
    
    /**
     * taskB()被调用时,该方法会被异步执行:会将任务交给线程池去完成
     */
    public void taskB() {
        System.out.println("BBBBBBBBBBB");
    }
}
复制代码

  3、如果在@Aysnc中没有指定线程池,会默认使用spring提供的默认线程池SimpleAsyncTaskExecutor

    缺点:线程池为每个任务都单独创建一个线程,不会重用线程。这样,就跟最原始实现异步的方式有了相同的缺点:异步处理业务太多时,同时运行的线程太多,可能导致服务器崩溃。

    因此,我们一定要创建自己的线程池,并给异步任务指定到哪个线程池去执行。

    创建线程池:

复制代码
@Configuration
public class ExecutorConfig {

    @Bean
    public Executor asyncServiceExecutor() {
        log.info("开始线程池:asyncServiceExecutor");
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //配置核心线程数
        executor.setCorePoolSize(50);
        //配置最大线程数
        executor.setMaxPoolSize(100);
        //配置队列大小
        executor.setQueueCapacity(99999);
        //配置线程池中的线程的名称前缀
        executor.setThreadNamePrefix("async-service-");
        // 设置拒绝策略:当pool已经达到max size的时候,如何处理新任务
        // CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //执行初始化
        executor.initialize();
        return executor;

    }
}
复制代码

  为任务指定线程池:

复制代码
public class AysncTask {

    /**
     * taskA()被调用时,该方法会被异步执行:会将任务交给线程池去完成
     */
    @Async("asyncServiceExecutor")
    public void taskA() {
        System.out.println("AAAAAAAA");
    }
    
    public void taskB() {
        System.out.println("BBBBBBBBBBB");
    }
}
复制代码

 

使用过程中的其他注意点:

  1、@Aysnc修饰的异步⽅法不能和调⽤此⽅法的方法放在⼀个类⾥⾯。

    如:@Aysnc修改的方法A(),在方法B()里调用方法A()。B()和A()不能在同一个类里。

  2、@Aysnc修饰的异步⽅法上加@Transactional将无法产生事务管理。因为异步方法单独开了一个线程导致的。

    解决办法:将需要做事务管理的代码单独写成一个方法,加上@Transactional,然后在异步调用方法中调用这个方法。

  3、可以为异步方法设置返回值,但必须是java.util.concurrent.Future类型,否则接收不到。如:Future的实现类:AsyncResult、CompletableFuture。

  

posted on   心里有爱眼里有光  阅读(2055)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
点击右上角即可分享
微信分享提示