1. 程式人生 > 其它 >@Async實現非同步任務

@Async實現非同步任務

1、@Async是SpringBoot自帶的一個執行步任務註解

@EnableAsync // 開啟非同步
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

2、同步執行

定義幾個方法,模擬耗時的操作

@Service
@Slf4j
public class ServiceDemoSync {
    public void taskOne() throws Exception {
        long start = System.currentTimeMillis();
        Thread.sleep(200);
        long end = System.currentTimeMillis();
        System.out.println("執行緒:" + Thread.currentThread().getName() + "任務1執行結束,總耗時={" + (end - start) + "} 毫秒");
    }

    public void taskTwo() throws Exception {
        long start = System.currentTimeMillis();
        Thread.sleep(200);
        long end = System.currentTimeMillis();
        System.out.println("執行緒:" + Thread.currentThread().getName() + "任務2執行結束,總耗時={" + (end - start) + "} 毫秒");
    }

    public void taskThere() throws Exception {
        long start = System.currentTimeMillis();
        Thread.sleep(200);
        long end = System.currentTimeMillis();
        System.out.println("執行緒:" + Thread.currentThread().getName() + "任務3執行結束,總耗時={" + (end - start) + "} 毫秒");
    }
}

測試一下

/**
 * @author qbb
 */
@SpringBootTest
public class ServiceTestSync {

    @Autowired
    private ServiceDemoSync serviceDemoSync;

    @Test
    public void test01() throws Exception {
        long start = System.currentTimeMillis();
        serviceDemoSync.taskOne();
        serviceDemoSync.taskTwo();
        serviceDemoSync.taskThere();
        Thread.sleep(200);
        long end = System.currentTimeMillis();
        System.out.println("總任務執行結束,總耗時={" + (end - start) + "} 毫秒");
    }

}

3、非同步執行

@Service
@Slf4j
public class ServiceDemo {

    @Async
    public void taskOne() throws Exception {
        long start = System.currentTimeMillis();
        Thread.sleep(200);
        long end = System.currentTimeMillis();
        System.out.println("執行緒:" + Thread.currentThread().getName() + "任務1執行結束,總耗時={" + (end - start) + "} 毫秒");
    }

    @Async
    public void taskTwo() throws Exception {
        long start = System.currentTimeMillis();
        Thread.sleep(200);
        long end = System.currentTimeMillis();
        System.out.println("執行緒:" + Thread.currentThread().getName() + "任務2執行結束,總耗時={" + (end - start) + "} 毫秒");
    }

    @Async
    public void taskThere() throws Exception {
        long start = System.currentTimeMillis();
        Thread.sleep(200);
        long end = System.currentTimeMillis();
        System.out.println("執行緒:" + Thread.currentThread().getName() + "任務3執行結束,總耗時={" + (end - start) + "} 毫秒");
    }
}
@SpringBootTest
public class ServiceTest {

    @Autowired
    private ServiceDemo serviceDemo;

    @Test
    public void test01() throws Exception {
        long start = System.currentTimeMillis();
        serviceDemo.taskOne();
        serviceDemo.taskTwo();
        serviceDemo.taskThere();
        Thread.sleep(200);
        long end = System.currentTimeMillis();
        System.out.println("總任務執行結束,總耗時={" + (end - start) + "} 毫秒");
    }

}

4、使用自定義執行緒池

package com.qbb.service;

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

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

/**
 * 自定義執行緒池
 */
@Configuration
public class ExecutorAsyncConfig {

    @Bean(name = "newAsyncExecutor")
    public Executor newAsync() {
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        // 設定核心執行緒數
        taskExecutor.setCorePoolSize(2);
        // 執行緒池維護執行緒的最大數量,只有在緩衝佇列滿了以後才會申請超過核心執行緒數的執行緒
        taskExecutor.setMaxPoolSize(10);
        // 快取佇列
        taskExecutor.setQueueCapacity(2);
        // 允許的空閒時間,當超過了核心執行緒數之外的執行緒在空閒時間到達之後會被銷燬
        taskExecutor.setKeepAliveSeconds(10);
        // 非同步方法內部執行緒名稱
        taskExecutor.setThreadNamePrefix("QIUQIU&LL-AsyncExecutor-");
        // 拒絕策略
        taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        taskExecutor.initialize();
        return taskExecutor;
    }
}

定義執行緒任務

@Component
@Slf4j
public class FutureTaskExecutor {

    @Async(value = "newAsyncExecutor")
    public Future<String> taskOne() {
        return new AsyncResult<>(Thread.currentThread().getName() + "one 完成");
    }

    @Async(value = "newAsyncExecutor")
    public Future<String> taskTwo() {
        return new AsyncResult<>(Thread.currentThread().getName() + "two 完成");
    }

    @Async
    public Future<String> taskThree() {
        return new AsyncResult<>(Thread.currentThread().getName() + "three 完成");
    }
}

測試一下

/**
 * @author qbb
 */
@SpringBootTest
@Slf4j
public class FutureTaskTestExecutor {
    @Autowired
    private FutureTaskExecutor futureTaskExecutor;

    @Test
    public void runAsync() throws Exception {
        long start = System.currentTimeMillis();
        Future<String> taskOne = futureTaskExecutor.taskOne();
        Future<String> taskTwo = futureTaskExecutor.taskTwo();
        Future<String> taskThere = futureTaskExecutor.taskThree();

        while (true) {
            if (taskOne.isDone() && taskTwo.isDone() && taskThere.isDone()) {
                System.out.println("任務1返回結果={" + (taskOne.get()) + "},任務2返回結果={" + (taskTwo.get()) + "},任務3返回結果={" + (taskThere.get()) + "}");
                break;
            }
        }
        long end = System.currentTimeMillis();
        System.out.println("總任務執行結束,總耗時={" + (end - start) + "} 毫秒");
    }
}

注意點:不生效的情況

1、@Async作用在static修飾的方法上不生效

2、呼叫非同步任務的方法和非同步方法在同一個類時不生效

@Service
@Slf4j
public class ServiceDemo {

    @Async
    public void taskOne() throws Exception {
        long start = System.currentTimeMillis();
        Thread.sleep(200);
        long end = System.currentTimeMillis();
        System.out.println("執行緒:" + Thread.currentThread().getName() + "任務1執行結束,總耗時={" + (end - start) + "} 毫秒");
    }

    @Async
    public void taskTwo() throws Exception {
        long start = System.currentTimeMillis();
        Thread.sleep(200);
        long end = System.currentTimeMillis();
        System.out.println("執行緒:" + Thread.currentThread().getName() + "任務2執行結束,總耗時={" + (end - start) + "} 毫秒");
    }

    @Async
    public void taskThere() throws Exception {
        long start = System.currentTimeMillis();
        Thread.sleep(200);
        long end = System.currentTimeMillis();
        System.out.println("執行緒:" + Thread.currentThread().getName() + "任務3執行結束,總耗時={" + (end - start) + "} 毫秒");
    }

    @Test
    public void test01() throws Exception {
        long start = System.currentTimeMillis();
        taskOne();
        taskTwo();
        taskThere();
        Thread.sleep(200);
        long end = System.currentTimeMillis();
        System.out.println("總任務執行結束,總耗時={" + (end - start) + "} 毫秒");
    }

}

還是推薦使用CompletableFuture實現非同步任務編排~~