@Asyncを使用して春ブーツ非同期呼び出し

最新の記事のための社会的関心と進歩しないん
JavaStorm.png

==順序定義の順序で実行される同期呼び出し理解されるように、非同期呼び出しは、同期呼び出しに対応し、一つの命令を実行するときに非同期呼び出しを呼び出しの終了を続行するのを待つ必要はありません。==

我々は説明する春のブートプロジェクトを作成します。特定の参照がプロジェクトコードをGitHubのことgithub.com/UniqueDong / ...非同期モジュール

ポンポン依存性は次のとおりです。

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <exclusions>
                <exclusion>
                    <artifactId>spring-boot-starter-logging</artifactId>
                    <groupId>org.springframework.boot</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <!-- logback -->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-access</artifactId>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.2</version>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
复制代码

次のようなクラスがある起動します。

@SpringBootApplication
public class AsyncApplication {

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

}
复制代码

カスタムスレッドプール

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.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 异步线程池
 */
@Configuration
@EnableAsync
public class AsyncExecutorConfig {

    /**
     * Set the ThreadPoolExecutor's core pool size.
     */
    private int corePoolSize = 8;
    /**
     * Set the ThreadPoolExecutor's maximum pool size.
     */
    private int maxPoolSize = 16;
    /**
     * Set the capacity for the ThreadPoolExecutor's BlockingQueue.
     */
    private int queueCapacity = 200;

    private String threadNamePrefix = "AsyncExecutor-";

    @Bean("taskExecutor")
    public Executor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(corePoolSize);
        executor.setMaxPoolSize(maxPoolSize);
        executor.setQueueCapacity(queueCapacity);
        executor.setKeepAliveSeconds(60);
        executor.setThreadNamePrefix(threadNamePrefix);

        // rejection-policy:当pool已经达到max size的时候,如何处理新任务  
        // CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行  
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }

}  

复制代码

私たちは、スレッドプールを作成するためのコードをThreadPoolTask​​Executor。次のようにパラメータの意味は以下のとおりです。

  • corePoolSize:作成されたスレッドプール内のコアスレッドの数
  • maxPoolSizeは:タスクの数がcorePoolSizeを超えるスレッドの数、スレッドプールのスレッドプール、およびバッファキューの最大数は、アプリケーションの後に満ちていました。
  • setKeepAliveSecondsは:到着のmaxPoolSizeスレッドアイドル時間が破壊されたときに、スレッドは60秒の時間をアイドルすることができます。
  • ThreadNamePrefix:接頭タスクスレッドの名前。
  • RejectedExecutionHandler:スレッドプールは、電源を処理していない場合は、このポリシーは、executeメソッドの呼び出し元のスレッドに直接拒否されたタスクを実行します。executorがシャットダウンされた場合、タスクが破棄されます

戦闘を使用してください

@Slf4j
@Service
public class OrderService {
    public static Random random = new Random();


    @Autowired
    private AsyncTask asyncTask;

    public void doShop() {
        try {
            createOrder();
            // 调用有结果返回的异步任务
            Future<String> pay = asyncTask.pay();
            if (pay.isDone()) {
                try {
                    String result = pay.get();
                    log.info("异步任务返回结果{}", result);
                } catch (ExecutionException e) {
                    e.printStackTrace();
                }
                asyncTask.vip();
                asyncTask.sendSms();
            }
            otherJob();
        } catch (InterruptedException e) {
            log.error("异常", e);
        }
    }

    public void createOrder() {
        log.info("开始做任务1:下单成功");
    }

    /**
     * 错误使用,不会异步执行:调用方与被调方不能在同一个类。主要是使用了动态代理,同一个类的时候直接调用,不是通过生成的动态代理类调用
     */
    @Async("taskExecutor")
    public void otherJob() {
        log.info("开始做任务4:物流");
        long start = System.currentTimeMillis();
        try {
            Thread.sleep(random.nextInt(10000));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        long end = System.currentTimeMillis();
        log.info("完成任务4,耗时:" + (end - start) + "毫秒");
    }

}
复制代码

非同期タスク・サービス・クラス

mport lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Component;

import java.util.Random;
import java.util.concurrent.Future;

@Component
@Slf4j
public class AsyncTask {
    public static Random random = new Random();


    @Async("taskExecutor")
    public void sendSms() throws InterruptedException {
        log.info("开始做任务2:发送短信");
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        log.info("完成任务1,耗时:" + (end - start) + "毫秒");
    }

    @Async("taskExecutor")
    public Future<String> pay() throws InterruptedException {
        log.info("开始做异步返回结果任务2:支付");
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        log.info("完成任务2,耗时:" + (end - start) + "毫秒");
        return new AsyncResult<>("会员服务完成");
    }

    /**
     * 返回结果的异步调用
     * @throws InterruptedException
     */
    @Async("taskExecutor")
    public void vip() throws InterruptedException {
        log.info("开始做任务5:会员");
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        log.info("开始做异步返回结果任务5,耗时:" + (end - start) + "毫秒");
    }
}
复制代码

ユニットテスト

@RunWith(SpringRunner.class)
@SpringBootTest(classes = AsyncApplication.class)
public class AsyncApplicationTests {

    @Autowired
    private OrderService orderService;

    @Test
    public void testAsync() {
        orderService.doShop();
        try {
            Thread.currentThread().join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}
复制代码

結果は

2019-05-16 20:25:06.577 [INFO ] [main] - zero.springboot.study.async.service.OrderService-52 开始做任务1:下单成功 
2019-05-16 20:25:06.586 [INFO ] [main] - zero.springboot.study.async.service.OrderService-60 开始做任务4:物流 
2019-05-16 20:25:06.599 [INFO ] [AsyncExecutor-1] - zero.springboot.study.async.service.AsyncTask-38 开始做异步返回结果任务2:支付 
2019-05-16 20:25:13.382 [INFO ] [AsyncExecutor-1] - zero.springboot.study.async.service.AsyncTask-42 完成任务2,耗时:6783毫秒 
2019-05-16 20:25:14.771 [INFO ] [main] - zero.springboot.study.async.service.OrderService-68 完成任务4,耗时:8184毫秒 
复制代码

いくつかは、スレッドプールのスレッドの名前は、我々が定義の前に付けることで表示される場合があり、説明は非同期実行スレッドプールを使用しています。これは私たちが間違ったユースケースを証明otherJob()を、そして非同期に実行されませんでした。

理由:

走査方式スキャンにスプリング含まれている場合Beanは、@Asyncノートを含む場合、ばねはサブクラスを生成する(すなわち、プロキシクラス、プロキシ)ビーン動的プロキシクラスのは、元のBeanを継承します。注釈付きメソッドが呼び出される。この時、で、実際には、エージェントクラスによって呼び出され、非同期呼び出しを増やすことでプロキシクラスの役割。しかし注釈付きメソッドは、同じクラスの他のメソッドを呼び出された場合、その後、プロキシクラスによって、しかし、直接、元Beanがメソッドを呼び出していない方法であって、これは増加非同期は存在しません役割は、私たちは、現象は@Asyncが無効ノートでご覧ください。


おすすめ

転載: blog.csdn.net/weixin_34376562/article/details/91386949