0Pricing
Spring Boot 4 Complete Guide · レッスン

@Asyncによる非同期メソッド

Springの`@Async`アノテーションとスレッドプールを使用して、メソッドを非同期に実行する方法を学習します。

「@Asyncによる非同期メソッド」はCoddyKit上の無料Spring Boot 4 Complete Guideレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはSpring Boot 4 Complete Guide学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Spring Boot 4 Complete Guideコースには全4レッスンが含まれています。

このレッスンの一部はまだ翻訳されておらず、英語で表示されています。

Intro to Async Operations

Imagine you're ordering food online. If the app made you wait for the chef to cook your meal before you could even browse other options, that would be a bad experience!

This is like synchronous operations: one task must finish before the next can start. It blocks the main flow.

Asynchronous operations, on the other hand, let you start a task and immediately move on to something else. The task runs in the background, and you get notified when it's done.

  • Non-blocking: Your application remains responsive.
  • Efficient: Better utilization of resources by performing multiple tasks concurrently.

Sync vs. Async Demo

Let's see a simple Java example of a blocking (synchronous) operation. Notice how the main thread waits for doSyncTask() to complete.

Try running this example:

public class Main {
  public static void main(String[] args) {
    System.out.println("Main thread: Starting sync task...");
    long startTime = System.currentTimeMillis();
    doSyncTask(); // This call blocks the main thread
    long endTime = System.currentTimeMillis();
    System.out.println("Main thread: Sync task finished in " + (endTime - startTime) + "ms.");
    System.out.println("Main thread: Continues immediately after sync task.");
  }

  public static void doSyncTask() {
    try {
      System.out.println("Sync task: Simulating work for 2 seconds...");
      Thread.sleep(2000); // Simulate a long operation
      System.out.println("Sync task: Completed!");
    } catch (InterruptedException e) {
      Thread.currentThread().interrupt();
      System.err.println("Sync task: Interrupted!");
    }
  }
}

Meet Spring's @Async

Spring Boot makes it incredibly simple to turn a synchronous method into an asynchronous one using the @Async annotation.

When you annotate a method with @Async:

  • Spring executes that method in a separate thread.
  • The calling method returns immediately, without waiting for the @Async method to finish.
  • You don't have to manage threads manually!

Activate @Async

Before you can use @Async, you need to enable asynchronous processing in your Spring Boot application. This is done by adding the @EnableAsync annotation.

You typically place @EnableAsync on your main application class or a dedicated configuration class.

Here's how to add it:

package com.coddykit.async;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;

@SpringBootApplication
@EnableAsync // This annotation activates @Async capability
public class AsyncApplication {
  public static void main(String[] args) {
    SpringApplication.run(AsyncApplication.class, args);
    System.out.println("Spring Boot application started with @EnableAsync!");
  }
}

@Async Method Basics

Once @EnableAsync is in place, you can simply add @Async to any public method in a Spring-managed component (like a @Service or @Component).

When performAsyncTask() is called, the main thread will print its next line immediately, while the async task runs in the background.

package com.coddykit.async;

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.annotation.EnableAsync;

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

  @Bean
  public CommandLineRunner run(MyAsyncTaskService service) {
    return args -> {
      System.out.println("Main thread: Calling async task...");
      service.performAsyncTask(); // This call returns immediately
      System.out.println("Main thread: Async task called, continuing immediately.");
      // Give the async task a chance to finish before the app exits
      Thread.sleep(3000);
    };
  }
}

@Service
class MyAsyncTaskService {
  @Async // Mark this method to run asynchronously
  public void performAsyncTask() {
    try {
      System.out.println("Async thread: Starting long task...");
      Thread.sleep(2000); // Simulate a long operation
      System.out.println("Async thread: Long task completed!");
    } catch (InterruptedException e) {
      Thread.currentThread().interrupt();
      System.err.println("Async thread: Task interrupted.");
    }
  }
}

How @Async Works

When you use @Async, Spring doesn't create a new thread for every call. Instead, it uses a thread pool.

  • A thread pool is a collection of pre-initialized threads that can execute tasks.
  • When an @Async method is called, Spring takes an available thread from the pool to execute it.
  • This avoids the overhead of creating new threads constantly and manages system resources efficiently.
  • By default, Spring uses a SimpleAsyncTaskExecutor, which can be inefficient for heavy loads.

Get Results with Future

What if your asynchronous method needs to return a result to the caller? You can't just return void or a direct value.

For this, you use java.util.concurrent.Future. The Future object acts as a placeholder for a result that isn't available yet.

  • The @Async method returns Future<T> (e.g., Future<String>).
  • The calling code can later call future.get() to retrieve the result (this call blocks until the result is ready).
  • You can also check future.isDone() to see if the task has completed without blocking.
package com.coddykit.async;

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.annotation.EnableAsync;
import java.util.concurrent.Future;
import java.util.concurrent.AsyncResult;

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

  @Bean
  public CommandLineRunner run(MyFutureTaskService service) {
    return args -> {
      System.out.println("Main thread: Calling async task with Future...");
      Future<String> futureResult = service.performFutureTask();
      System.out.println("Main thread: Async task called, continuing immediately.");

      // Main thread can do other work while async task runs
      System.out.println("Main thread: Doing other work...");
      Thread.sleep(500);

      // Wait for the result (this loop checks, future.get() blocks)
      while(!futureResult.isDone()) {
        System.out.println("Main thread: Waiting for async result...");
        Thread.sleep(500);
      }
      String result = futureResult.get(); // Retrieves the result (blocks if not done)
      System.out.println("Main thread: Received result: " + result);
    };
  }
}

@Service
class MyFutureTaskService {
  @Async
  public Future<String> performFutureTask() {
    try {
      System.out.println("Async thread: Starting Future task...");
      Thread.sleep(2000); // Simulate a long operation
      System.out.println("Async thread: Future task completed!");
      return new AsyncResult<>("Task finished successfully!");
    } catch (InterruptedException e) {
      Thread.currentThread().interrupt();
      return new AsyncResult<>("Task interrupted!");
    }
  }
}

Async Error Handling

When an @Async method (especially a void one) throws an exception, it's not propagated back to the calling thread by default. This means the exception might be silently swallowed, making debugging difficult.

To properly handle exceptions in @Async methods, you can implement AsyncConfigurer and provide a custom AsyncUncaughtExceptionHandler.

  • This handler catches any exceptions thrown by @Async methods.
  • It allows you to log errors, send notifications, or perform other error recovery actions.
  • For methods returning Future, the exception is wrapped in the Future and thrown when future.get() is called.

Custom Thread Pool

For production applications, it's crucial to configure your own thread pool (Executor) for @Async. This gives you control over resources and performance.

You define a ThreadPoolTaskExecutor bean and specify its properties:

  • corePoolSize: The minimum number of threads to keep alive.
  • maxPoolSize: The maximum number of threads the pool can contain.
  • queueCapacity: The capacity of the queue for tasks waiting to be executed.
  • threadNamePrefix: A prefix for the names of threads in this pool, useful for logging.

You can then specify which executor to use with @Async("executorBeanName").

package com.coddykit.async;

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;

@Configuration
@EnableAsync
public class AsyncConfig {
  @Bean(name = "customAsyncExecutor")
  public Executor customAsyncExecutor() {
    ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    executor.setCorePoolSize(2); // Keep 2 threads always running
    executor.setMaxPoolSize(5);  // Allow up to 5 threads if demand is high
    executor.setQueueCapacity(10); // Queue up to 10 tasks if all threads are busy
    executor.setThreadNamePrefix("CustomAsync-"); // Helps identify threads in logs
    executor.initialize();
    return executor;
  }

  // To use this, you'd annotate your async method like this:
  // @Async("customAsyncExecutor")
  // public void myCustomAsyncMethod() { /* ... */ }
}

Async Quick Check

Let's check your understanding of Spring's @Async annotation.

Lesson Summary

Well done! You've learned the fundamentals of asynchronous processing with Spring Boot's @Async.

  • We saw how synchronous operations block, while asynchronous operations allow non-blocking execution.
  • The @EnableAsync annotation activates asynchronous method processing.
  • The @Async annotation on a method ensures it runs in a separate thread.
  • For returning results from async methods, we use Future<T>.
  • Custom ThreadPoolTaskExecutor beans allow fine-grained control over thread pool behavior.

Next, we'll dive into message queues, a powerful way to decouple services and handle asynchronous communication at a larger scale.

よくある質問

「@Asyncによる非同期メソッド」レッスンは無料ですか?

はい。「@Asyncによる非同期メソッド」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Spring Boot 4 Complete Guideコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Spring Boot 4 Complete Guideコースには全4レッスンが含まれています。

「@Asyncによる非同期メソッド」で何を学びますか?

Springの`@Async`アノテーションとスレッドプールを使用して、メソッドを非同期に実行する方法を学習します。 ブラウザで直接実行するハンズオンコードでSpring Boot 4 Complete Guideを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Spring Boot 4 Complete Guideを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのSpring Boot 4 Complete Guideは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。

「@Asyncによる非同期メソッド」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このSpring Boot 4 Complete Guideレッスンでコードを書いて実行できますか?

はい。すべてのSpring Boot 4 Complete Guideレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. @Asyncによる非同期メソッド
  2. メッセージキュー入門
  3. RabbitMQとKafkaの統合
  4. @Scheduledによるタスクのスケジューリング
← Spring Boot 4 Complete Guideに戻る