springboot之異步任務


springboot之異步任務

啟動類:添加@EnableAsync注解

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

 

異步任務執行類 添加@Async注解

import java.util.concurrent.Future;
 
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Component;
 
/**
 * 功能描述:異步任務業務類(@Async也可添加在方法上,@Async放在類上,表示類內方法皆為異步方法)
 */
@Component
@Async("taskExecutor")//使用自己的線程池記得括號內填寫線程池bean的名字,詳見下邊線程池配置;如果使用默認線程池,則直接使用@Async
public class AsyncTask {
    
 
    //獲取異步結果
    public Future<String> task4() throws InterruptedException{
        long begin = System.currentTimeMillis();
        Thread.sleep(2000L);
        long end = System.currentTimeMillis();
        System.out.println("任務4耗時="+(end-begin));
        return new AsyncResult<String>("任務4");
    }
    
    
    public Future<String> task5() throws InterruptedException{
        long begin = System.currentTimeMillis();
        Thread.sleep(3000L);
        long end = System.currentTimeMillis();
        System.out.println("任務5耗時="+(end-begin));
        return new AsyncResult<String>("任務5");
    }
    
    public Future<String> task6() throws InterruptedException{
        long begin = System.currentTimeMillis();
        Thread.sleep(1000L);
        long end = System.currentTimeMillis();
        System.out.println("任務6耗時="+(end-begin));
        return new AsyncResult<String>("任務6");
    }
        
}

 

異步線程池

package com.boot.common.conf;
 
import java.util.concurrent.ThreadPoolExecutor;
 
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
 
/**
 * 線程池配置(線程池可以不配置,使用默認線程池,注意:在異步方法或類添加@Async注解是:@Async;如果自己配置了線程池,異步方法或類使用自己配置的線程池,則注解應為:@Async("taskExecutor")括號內為自己配置的線程池對象bean的名字)
 * @author zhh
 *
 */
@Configuration
@EnableAsync
public class ThreadPoolTaskConfig {
    
    private static final int corePoolSize = 10;               // 核心線程數(默認線程數)線程池創建時候初始化的線程數
    private static final int maxPoolSize = 100;                // 最大線程數 線程池最大的線程數,只有在緩沖隊列滿了之后才會申請超過核心線程數的線程
    private static final int keepAliveTime = 10;            // 允許線程空閑時間(單位:默認為秒)當超過了核心線程之外的線程在空閑時間到達之后會被銷毀
    private static final int queueCapacity = 200;            // 緩沖隊列數 用來緩沖執行任務的隊列
    private static final String threadNamePrefix = "Async-Service-"; // 線程池名前綴 方便我們定位處理任務所在的線程池
    
    @Bean("taskExecutor") // bean的名稱,默認為首字母小寫的方法名
    public ThreadPoolTaskExecutor taskExecutor(){
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(corePoolSize);   
        executor.setMaxPoolSize(maxPoolSize);
        executor.setQueueCapacity(queueCapacity);
        executor.setKeepAliveSeconds(keepAliveTime);
        executor.setThreadNamePrefix(threadNamePrefix);
        
        // 線程池對拒絕任務的處理策略 采用了CallerRunsPolicy策略,當線程池沒有處理能力的時候,該策略會直接在 execute 方法的調用線程中運行被拒絕的任務;如果執行程序已關閉,則會丟棄該任務
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 初始化
        executor.initialize();
        return executor;
    }
}

 

異步任務調用

import java.util.concurrent.Future;
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.jincou.task.AsyncTask;
import com.jincou.util.JsonData;

@RestController
@RequestMapping("/api/v1")
public class UserController {
    
    @Autowired
    private AsyncTask task;
    
    @GetMapping("async_task")
    public JsonData exeTask() throws InterruptedException{
        
        long begin = System.currentTimeMillis();
        
        Future<String> task4 = task.task4();
        Future<String> task5 = task.task5();
        Future<String> task6 = task.task6();
        
        /**
         *如果需要監控異步任務是否完成,可以使用以下方式
        **/
        //如果都執行完成就可以跳出循環,isDone方法如果此任務完成,true
        for(;;){
            if (task4.isDone() && task5.isDone() && task6.isDone()) {
                break;
            }
        }
       
        long end = System.currentTimeMillis();    
        long total = end-begin;
        System.out.println("執行總耗時="+total);
        return JsonData.buildSuccess(total);
    }    
}

 

注意事項:

優點:使用異步任務比同步任務耗時少,提高后台處理性能。
如下方式會使@Async失效
一、異步方法使用static修飾
二、異步類沒有使用@Component注解(或其他注解)導致spring無法掃描到異步類
三、異步方法不能與調用異步方法的方法在同一個類中
四、類中需要使用@Autowired或@Resource等注解自動注入,不能自己手動new對象
五、如果使用SpringBoot框架必須在啟動類中增加@EnableAsync注解
六、在Async 方法上標注@Transactional是沒用的。 在Async 方法調用的方法上標注@Transactional 有效。

原文摘自:https://blog.csdn.net/k0307x1990y/article/details/91950584


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM