Spring Bootでparallelや@EnableAsyncで非同期処理や並列処理を実装する

Spring Bootでparallelや@EnableAsyncで非同期処理や並列処理を実装する

Stream APIで並列処理を実装する

Java8以上の場合、stream apiでparallelメソッドで並列実行することが出来ます。

parallelメソッドは並列処理ですので非同期処理とは異なります。

以下ソースは、指定秒数かかるAPIを2回実行していますが、並列実行しているので指定秒数強で実行ができます。

/**
* 指定秒数かかるAPI
*
* @param seconds
* @return
* @throws InterruptedException
*/
@RequestMapping(path = "/sleep/{seconds}", method = RequestMethod.GET)
public ResponseEntity<String> sleep(@PathVariable String seconds) throws InterruptedException {
Thread.sleep(Long.valueOf(seconds) * 1000L); // スリープするだけ
return ResponseEntity.ok("test");
}
/**
* parallelで並列実行
*
* @param seconds
* @return
*/
@RequestMapping(path = "/test/{seconds}", method = RequestMethod.GET)
public ResponseEntity<String> test(@PathVariable String seconds) {
long startTime = System.currentTimeMillis();
RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder();
RestTemplate restTemplate = restTemplateBuilder.build();
String url = String.format("http://localhost:8080/sleep/%s", seconds);
List<String> list = List.of(url, url); // 並列
String result =
list.stream()
.parallel()
.map(
e > {
return restTemplate.getForObject(url, String.class);
})
.collect(Collectors.joining(",", "{", "}"));
long endTime = System.currentTimeMillis();
System.out.println("処理時間:" + (endTime startTime) + " ms");
return ResponseEntity.ok(result);
}

view raw
Sample.java
hosted with ❤ by GitHub

Spring5ではAsyncRestTemplateは非推奨となっているようです。

https://spring.pleiades.io/spring/docs/current/javadoc-api/deprecated-list.html

@EnableAsync,@Asyncアノテーションを使用して非同期処理を実装する

Spring Bootで非同期処理を実装するには@EnableAsyncアノテーションを使用します。

起動クラスに@EnableAsyncアノテーションを付与します。これで@Asyncアノテーションを付与したメソッドが非同期で実行されるようになります。

package jp.co.confrage;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
@SpringBootApplication
@EnableAsync
public class AsyncControllerApplication {
public static void main(String[] args) {
SpringApplication.run(AsyncControllerApplication.class, args);
}
}

コントローラから非同期処理をするasyncメソッドを3回呼び出しています。指定秒数かかるメソッドです。

package jp.co.confrage.presentation.controller;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import jp.co.confrage.presentation.service.DemoService;
import lombok.RequiredArgsConstructor;
@RestController
@RequiredArgsConstructor
public class DemoController {
private final DemoService demoService;
/**
* 指定秒数かかるAPI
*
* @param seconds1
* @param seconds2
* @param seconds3
* @return
* @throws InterruptedException
* @throws ExecutionException
*/
@RequestMapping(path = "/sleep/{seconds1}/{seconds2}/{seconds3}", method = RequestMethod.GET)
public ResponseEntity<String> sleep(
@PathVariable String seconds1, @PathVariable String seconds2, @PathVariable String seconds3)
throws InterruptedException, ExecutionException {
long startTime = System.currentTimeMillis();
CompletableFuture<String> page1 = demoService.async(seconds1);
CompletableFuture<String> page2 = demoService.async(seconds2);
CompletableFuture<String> page3 = demoService.async(seconds3);
CompletableFuture.allOf(page1, page2, page3).join(); // 終了まで待機する
System.out.println("–> " + page1.get());
System.out.println("–> " + page2.get());
System.out.println("–> " + page3.get());
long endTime = System.currentTimeMillis();
System.out.println("処理時間:" + (endTime startTime) + " ms");
return ResponseEntity.ok("test");
}
}

view raw
DemoController.java
hosted with ❤ by GitHub

@Asyncアノテーションが付与されたメソッドは別スレッドで実行されます。以下サービスクラスです。

package jp.co.confrage.presentation.service;
import java.util.concurrent.CompletableFuture;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
@Service
public class DemoService {
/**
* 非同期処理
*
* @param seconds
* @return
* @throws InterruptedException
*/
@Async
public CompletableFuture<String> async(String seconds) throws InterruptedException {
Thread.sleep(Long.valueOf(seconds) * 1000L);
return CompletableFuture.completedFuture(seconds + "秒かかる処理");
}
}

view raw
DemoService.java
hosted with ❤ by GitHub

以下実行例です。

@Asyncアノテーションをコメントアウトした場合の実行例です。同期処理されるため、実行時間がかかっています。

以下サイトによるとorg.springframework.core.task.TaskExecutorクラスで色々調整が可能です。

また、実行可能jarでもwarでも実装可能です。

https://spring.pleiades.io/guides/gs/async-method/

サンプルコード

  • このエントリーをはてなブックマークに追加
  • Evernoteに保存Evernoteに保存

コメントをどうぞ

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA