Spring Boot非同期呼出し@Asyncプロセス詳細


実際の開発では、要求と応答をタイムリーに処理するために、マルチタスクを同時に実行したり、メインタスクを先に処理したりすることがあります。すなわち、非同期呼び出しの実現は、マルチスレッド、タイミングタスク、メッセージキューなど、多くのことがあります。
私たちは@Async非同期方法の呼び出しを話します。
一、@Ayncはデモンストレーションを使います。
@AsyncはSpring内蔵の注釈で、非同期のタスクを処理するためにSpring Bootで同様に適用され、Spring Bootプロジェクトでは、boot自体のstarterを除いて、追加的な依存を導入する必要がありません。
@Ayncを使うには、スタートクラスに@EnbleAsyncを加えて、非同期的な方法を開く必要があります。

@EnableAsync
@SpringBootApplication
public class SpringbootApplication {

  public static void main(String[] args) {
    SpringApplication.run(SpringbootApplication.class, args);
  }
}
現在の休暇には3つのタスクがあります。それぞれAyncTask類のtaskOne、tasktwo、taskThre方法に対応しています。ここでスレッドのsleepを作って実際の運行をシミュレートします。

@Slf4j
@Component
public class AsyncTask {

  private Random random = new Random();
  
  public void taskOne() throws InterruptedException {
    long start = System.currentTimeMillis();
    Thread.sleep(random.nextInt(10000));
    long end = System.currentTimeMillis();
    log.info("         {} ", (end - start)/1000f);
  }
  
  public void taskTwo() throws InterruptedException {
    long start = System.currentTimeMillis();
    Thread.sleep(random.nextInt(10000));
    long end = System.currentTimeMillis();
    log.info("         {} ", (end - start)/1000f);
  }
  
  public void taskThree() throws InterruptedException {
    long start = System.currentTimeMillis();
    Thread.sleep(random.nextInt(10000));
    long end = System.currentTimeMillis();
    log.info("         {} ", (end - start)/1000f);
  }
}
そしてテストクラスを作成します。@AsyncコメントはSpring容器を起動してから有効になります。ここではテストクラスはSpring Bootのtestバッグの下に置いて、Spring BootTestを使いました。

@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest(classes = SpringbootApplication.class)
public class AsyncTaskTest {

  @Autowired
  private AsyncTask asyncTask;

  @Test
  public void doAsyncTasks(){
    try {
      long start = System.currentTimeMillis();
      asyncTask.taskOne();
      asyncTask.taskTwo();
      asyncTask.taskThree();
      Thread.sleep(5000);
      long end = System.currentTimeMillis();
      log.info("         {} ", (end - start)/1000f);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }

}
テスト方法を実行して、コンソールで任務の一、二、三を見て順番に実行して、最後のメインプログラムは完成して、これは私達の予想と同じで、私達はいかなる追加の処理がないので、彼らは普通の方法で、コード順に順次実行します。

タスクを同時に実行するには、タスクメソッド上で@Aync注釈を使うだけでいいです。注意したいのは@Ayncで修飾された方法はstaticタイプと定義しないでください。このような非同期呼び出しは有効になりません。

@Slf4j
@Component
public class AsyncTask {

  private Random random = new Random();

  //@Async           static  ,          
  @Async
  public void taskOne() throws InterruptedException {
    long start = System.currentTimeMillis();
    Thread.sleep(random.nextInt(10000));
    long end = System.currentTimeMillis();
    log.info("         {} ", (end - start)/1000f);
  }

  @Async
  public void taskTwo() throws InterruptedException {
    long start = System.currentTimeMillis();
    Thread.sleep(random.nextInt(10000));
    long end = System.currentTimeMillis();
    log.info("         {} ", (end - start)/1000f);
  }

  @Async
  public void taskThree() throws InterruptedException {
    long start = System.currentTimeMillis();
    Thread.sleep(random.nextInt(10000));
    long end = System.currentTimeMillis();
    log.info("         {} ", (end - start)/1000f);
  }

}
そして私たちはテストクラスを実行しています。この時は出力が多様になるかもしれません。どのタスクでも先に実行してしまうかもしれません。メインプログラムが閉じているので出力しない方法もあります。

二、Futureは非同期実行結果を取得する
上で@Asyncをデモしましたが、タスクの同時スケジューリングが必要な場合以外に、タスクの戻り値を取得し、マルチタスクを全部実行してからメインタスクを終了する場合はどうすればいいですか?
マルチスレッドではCallableとFutureを通じて戻り値を取得できます。ここも同様です。私たちはFutureリターン方法を使って実行した結果、AyncResoultはFutureの一つの実現クラスです。

@Slf4j
@Component
public class FutureTask {

  private Random random = new Random();

  //@Async           static  ,          
  @Async
  public Future<String> taskOne() throws InterruptedException {
    long start = System.currentTimeMillis();
    Thread.sleep(random.nextInt(10000));
    long end = System.currentTimeMillis();
    log.info("         {} ", (end - start)/1000f);
    return new AsyncResult <>("   Ok");
  }

  @Async
  public Future<String> taskTwo() throws InterruptedException {
    long start = System.currentTimeMillis();
    Thread.sleep(random.nextInt(10000));
    long end = System.currentTimeMillis();
    log.info("         {} ", (end - start)/1000f);
    return new AsyncResult <>("   OK");
  }

  @Async
  public Future<String> taskThree() throws InterruptedException {
    long start = System.currentTimeMillis();
    Thread.sleep(random.nextInt(10000));
    long end = System.currentTimeMillis();
    log.info("         {} ", (end - start)/1000f);
    return new AsyncResult <>("   Ok");
  }
}
Async Resoultで:
  • isDowne()方法は、非同期方法が実行されたかどうかを判断するために使用され、タスクが完了したら、true
  • に戻る。
  • get()方法は、タスク実行後に戻った結果
  • を取得するために使用できます。
  • キャンセルジョブに使用できます。パラメータmayInterrupt IfRunningは実行中のジョブをキャンセルすることができるかどうかを示しています。trueを設定すると、実行中のジョブをキャンセルすることができます。
  • isCarcelled()メソッドは、ジョブがキャンセルされたかどうかを示し、正常に完了する前にキャンセルされた場合、true
  • に戻ります。
  • get(long timeout、TimeUnit unit)は、実行結果を取得するために使用され、指定された時間内に結果が得られない場合は、直接null
  • に戻る。
    
    @Slf4j
    @RunWith(SpringRunner.class)
    @SpringBootTest(classes = SpringbootApplication.class)
    public class AsyncTaskTest {
    
      @Autowired
      private FutureTask futureTask;
    
      @Test
      public void doFutureTasks(){
        try {
          long start = System.currentTimeMillis();
          Future <String> future1 = futureTask.taskOne();
          Future <String> future2 = futureTask.taskTwo();
          Future <String> future3 = futureTask.taskThree();
          //3               
          do {
            Thread.sleep(100);
          } while (future1.isDone() && future2.isDone() && future3.isDone());
          log.info("          :{}", future1.get());
          Thread.sleep(5000);
          long end = System.currentTimeMillis();
          log.info("         {} ", (end - start)/1000f);
        } catch (InterruptedException e) {
          e.printStackTrace();
        } catch (ExecutionException e) {
          e.printStackTrace();
        }
      }
    }
    テストクラスを実行して、私達はタスクの1、3歩が実行され、メインタスクの最後の実行が完了し、タスクの戻り情報が得られます。

    ソースアドレス:https://github.com/imyanger/springboot-project/tree/master/p23-springboot-async
    以上が本文の全部です。皆さんの勉強に役に立つように、私たちを応援してください。