Try using it in your preferred language.

English

  • English
  • 汉语
  • Español
  • Bahasa Indonesia
  • Português
  • Русский
  • 日本語
  • 한국어
  • Deutsch
  • Français
  • Italiano
  • Türkçe
  • Tiếng Việt
  • ไทย
  • Polski
  • Nederlands
  • हिन्दी
  • Magyar
translation

Dies ist ein von KI übersetzter Beitrag.

제이온

[Spring] @Async-Verwendungsmethode

  • Schreibsprache: Koreanisch
  • Referenzland: Alle Länder country-flag

Sprache auswählen

  • Deutsch
  • English
  • 汉语
  • Español
  • Bahasa Indonesia
  • Português
  • Русский
  • 日本語
  • 한국어
  • Français
  • Italiano
  • Türkçe
  • Tiếng Việt
  • ไทย
  • Polski
  • Nederlands
  • हिन्दी
  • Magyar

Von durumis AI zusammengefasster Text

  • Erklärt die Verwendung von Spring @Async zur Implementierung der asynchronen Verarbeitung in Java, einschließlich der Vorteile und Vorsichtsmaßnahmen.
  • Mit Spring @Async können Sie durch Hinzufügen der @EnableAsync-Annotation und Anbringen der @Async-Annotation an die Methoden, für die Sie die asynchrone Verarbeitung wünschen, die asynchrone Verarbeitung einfach implementieren.
  • Mithilfe der Thread-Pool-Einstellungen ist eine effiziente Thread-Verwaltung möglich. Je nach Rückgabetyp können Sie Future, ListenableFuture oder CompletableFuture verwenden, um die Ergebnisse der asynchronen Verarbeitung zurückzugeben.

Java asynchrone Verarbeitung

Bevor wir uns Spring @Async ansehen, sind die Konzepte von synchron, asynchron und Multithreading unerlässlich. Angenommen, Sie kennen diese Konzepte. Lassen Sie uns die Methode der asynchronen Verarbeitung von reinem Java anhand von Code untersuchen. Wenn Sie mit Java-Threads vertraut sind, können Sie dieses Kapitel überspringen.


public class MessageService {

    public void print(String message) {
        System.out.println(message);
    }
}

public class Main {

    public static void main(String[] args) {
        MessageService messageService = new MessageService();

        for (int i = 1; i <= 100; i++) {
            messageService.print(i + "");
        }
    }


Wenn Sie eine Funktion erstellen, die eine Nachricht empfängt und einfach ausgibt, können Sie den Code wie oben schreiben, wenn Sie die synchrone Methode verwenden. Wenn Sie dies in eine asynchrone Methode mit Multithreading ändern, Sie können den Quellcode wie folgt schreiben.


public class MessageService {

    public void print(String message) {
        new Thread(() -> System.out.println(message))
                .start();
    }
}

public class Main {

    public static void main(String[] args) {
        MessageService messageService = new MessageService();

        for (int i = 1; i <= 100; i++) {
            messageService.print(i + "");
        }
    }


Diese Methode ist jedoch sehr riskant, da Threads nicht verwaltet werden können. Wenn beispielsweise 10.000 Aufrufe gleichzeitig erfolgen, müssen in sehr kurzer Zeit 10.000 Threads erstellt werden. Die Kosten für das Erstellen von Threads sind nicht gering, was sich negativ auf die Leistung des Programms auswirken kann und sogar zu einem OOM-Fehler führen kann. Daher müssen Sie einen Thread-Pool implementieren, um Threads zu verwalten. Java bietet die ExecutorService-Klasse.


public class MessageService {

    private final ExecutorService executorService = Executors.newFixedThreadPool(10);

    public void print(String message) {
        executorService.submit(() -> System.out.println(message));
    }
}

public class Main {

    public static void main(String[] args) {
        MessageService messageService = new MessageService();

        for (int i = 1; i <= 100; i++) {
            messageService.print(i + "");
        }
    }


Die Gesamtzahl der Threads ist auf 10 begrenzt, und wir konnten die asynchrone Verarbeitung nach der Multithreading-Methode korrekt durchführen. Diese Methode erfordert jedoch, dass die submit()-Methode von ExecutorService auf jede Methode angewendet wird, die asynchron verarbeitet werden soll. Dies führt zu wiederholten Änderungen. Das heißt, wenn Sie eine synchron erstellte Methode asynchron ändern möchten, ist eine Änderung der Logik der Methode selbst erforderlich.


Spring @Async

Einfache Methode

@EnableAsync
@SpringBootApplication
public class DemoApplication {

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

}

@Service
public class MessageService {

    @Async
    public void print(String message) {
        System.out.println(message);
    }
}

@RequiredArgsConstructor
@RestController
public class MessageController {

    private final MessageService messageService;

    @GetMapping("/messages")
    @ResponseStatus(code = HttpStatus.OK)
    public void printMessage() {
        for (int i = 1; i <= 100; i++) {
            messageService.print(i + "");
        }
    }


Fügen Sie einfach die @EnableAsync-Annotation über der Application-Klasse und die @Async-Annotation über der synchronen Logikmethode hinzu, die Sie asynchron verarbeiten möchten. Diese Methode hat jedoch das Problem, dass Threads nicht verwaltet werden. Denn Die Standardeinstellung von @Async ist die Verwendung von SimpleAsyncTaskExecutor, bei dem es sich nicht um einen Thread-Pool handelt, sondern einfach um die Erstellung von Threads.


Verwenden Sie den Thread-Pool

Entfernen Sie zunächst @EnableAsync aus der Application-Klasse. Wenn die Application-Klasse die @EnableAutoConfiguration- oder @SpringBootApplication-Konfiguration enthält, liest sie zur Laufzeit die Bean-Informationen der SpringAsyncConfig-Klasse (die wir später erstellen werden), die mit @Configuration konfiguriert ist. threadPoolTaskExecutor bean information.


@Configuration
@EnableAsync // Muss an der Async-Konfigurationsklasse und nicht an der Anwendung angebracht werden.
public class SpringAsyncConfig {

    @Bean(name = "threadPoolTaskExecutor")
    public Executor threadPoolTaskExecutor() {
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        taskExecutor.setCorePoolSize(3); // Anzahl der Basistreads
        taskExecutor.setMaxPoolSize(30); // Maximale Anzahl der Threads
        taskExecutor.setQueueCapacity(100); // Queue-Größe
        taskExecutor.setThreadNamePrefix("Executor-");
        return taskExecutor;
    }


Sie können Core- und Max-Größen festlegen. In diesem Fall wird erwartet, dass die Größe des Cores initialisiert wird und die Anzahl der Threads im Falle einer Überlastung der Verarbeitung auf die maximale Größe erhöht wird, aber dies ist nicht der Fall.


Intern wird eine LinkedBlockingQueue mit der Größe Integer.MAX_VALUE erstellt, sodass Aufgaben in der Warteschlange gehalten werden, wenn die Threads der Größe Core keine Aufgaben verarbeiten können. Wenn die Warteschlange voll ist, werden Threads der Größe Max erstellt, um die Aufgaben zu verarbeiten.


Wenn Sie eine Queue-Größe von Integer.MAX_VALUE nicht verwenden möchten, können Sie queueCapacity festlegen. Wenn Sie diese Einstellung verwenden, werden die Aufgaben zunächst mit 3 Threads verarbeitet. Wenn die Verarbeitungsgeschwindigkeit niedrig ist, werden die Aufgaben in einer Warteschlange mit einer Größe von 100 gehalten. Wenn weitere Anfragen eingehen, werden maximal 30 Threads erstellt, um die Aufgaben zu verarbeiten.


Wenn die Thread-Pool-Konfiguration abgeschlossen ist, können Sie den Namen der Bean in der Methode mit der @Async-Annotation angeben.


@Service
public class MessageService {

    @Async("threadPoolTaskExecutor")
    public void print(String message) {
        System.out.println(message);
    }


Wenn Sie mehrere Thread-Pool-Typen konfigurieren möchten, erstellen Sie mehrere Bean-Erstellungsmethoden wie threadPoolTaskExecutor() und fügen Sie die gewünschte Thread-Pool-Bean bei der Konfiguration von @Async hinzu.


Formular, das je nach Rückgabetyp zurückgegeben wird

Kein Rückgabewert

Dies ist der Fall, wenn die Methode, die asynchron verarbeitet werden soll, kein Verarbeitungsergebnis zurückgeben muss. In diesem Fall können Sie den Rückgabetyp der @Async-Annotation auf void setzen.


Rückgabewert vorhanden

Sie können die Typen Future, ListenableFuture und CompletableFuture als Rückgabetypen verwenden. Sie können das Rückgabeformat der asynchronen Methode mit new AsyncResult() bündeln.


[Future]

@Service
public class MessageService {

    @Async
    public Future print(String message) throws InterruptedException {
        System.out.println("Task Start - " + message);
        Thread.sleep(3000);
        return new AsyncResult<>("jayon-" + message);
    }
}

@RequiredArgsConstructor
@RestController
public class MessageController {

    private final MessageService messageService;

    @GetMapping("/messages")
    @ResponseStatus(code = HttpStatus.OK)
    public void printMessage() throws ExecutionException, InterruptedException {
        for (int i = 1; i <= 5; i++) {
            Future future = messageService.print(i + "");
            System.out.println(future.get());
        }
    }
}

// Ausführungsergebnis
Task Start - 1
jayon-1
Task Start - 2
jayon-2
Task Start - 3
jayon-3
Task Start - 4
jayon-4
Task Start - 5


future.get() wartet blockierend, bis das Ergebnis der Anfrage eintrifft. Daher wird es zu einer asynchronen Blockierungsmethode, die eine schlechte Leistung erbringt. Normalerweise wird Future nicht verwendet.


[ListenableFuture]

@Service
public class MessageService {

    @Async
    public ListenableFuture print(String message) throws InterruptedException {
        System.out.println("Task Start - " + message);
        Thread.sleep(3000);
        return new AsyncResult<>("jayon-" + message);
    }
}

@RequiredArgsConstructor
@RestController
public class MessageController {

    private final MessageService messageService;

    @GetMapping("/messages")
    @ResponseStatus(code = HttpStatus.OK)
    public void printMessage() throws InterruptedException {
        for (int i = 1; i <= 5; i++) {
            ListenableFuture listenableFuture = messageService.print(i + "");
            listenableFuture.addCallback(System.out::println, error -> System.out.println(error.getMessage()));
        }
    }
}

// Ausführungsergebnis
Task Start - 1
Task Start - 3
Task Start - 2
jayon-1
jayon-2
Task Start - 5
jayon-3
Task Start - 4
jayon-4


ListenableFuture ermöglicht die Verarbeitung von Aufgaben auf nicht blockierende Weise über Callbacks. Der erste Parameter der addCallback()-Methode definiert die Callback-Methode für den Task-Abschluss, der zweite Parameter definiert die Callback-Methode für den Task-Fehler. Beachten Sie, dass die Anzahl der Core-Threads im Thread-Pool auf 3 festgelegt ist, daher können Sie sehen, dass die Nachricht „Task Start“ zuerst 3 Mal ausgegeben wird.



[CompletableFuture]

Mit ListenableFuture allein können Sie eine nicht blockierende Logik implementieren, aber wenn Sie in Callbacks Callbacks benötigen, führt dies zu sehr komplexem Code, der als Callback-Hölle bezeichnet wird.


Untitled


In dieser Sitzung werden wir uns nicht mit CompletableFuture befassen. Wenn Sie an Code interessiert sind, der komplexe Callbacks behandelt, lesen Sie bitte den Link in der Quelle unten.


@Service
public class MessageService {

    @Async
    public CompletableFuture print(String message) throws InterruptedException {
        System.out.println("Task Start - " + message);
        Thread.sleep(3000);
        return new AsyncResult<>("jayon-" + message).completable();
    }
}

@RequiredArgsConstructor
@RestController
public class MessageController {

    private final MessageService messageService;

    @GetMapping("/messages")
    @ResponseStatus(code = HttpStatus.OK)
    public void printMessage() throws InterruptedException {
        for (int i = 1; i <= 5; i++) {
            CompletableFuture completableFuture = messageService.print(i + "");
            completableFuture
                    .thenAccept(System.out::println)
                    .exceptionally(error -> {
                        System.out.println(error.getMessage());
                        return null;
                    });
        }
    }


Die Lesbarkeit ist besser als die Definition von Callbacks für ListenableFuture und die nicht blockierende Funktion wird vollständig ausgeführt. Daher wird empfohlen, CompletableFuture zu verwenden, wenn Sie einen Rückgabewert verwenden möchten, wenn Sie @Async verwenden.


Vorteile von @Async

Entwickler können Methoden synchron schreiben und müssen nur die @Async-Annotation über die Methode setzen, wenn sie asynchron sind. Dadurch können Sie Code erstellen, der in Bezug auf synchron und asynchron gut zu warten ist.


Vorsichtsmaßnahmen bei @Async

Um die @Async-Funktion zu verwenden, müssen Sie die @EnableAsync-Annotation deklarieren. Wenn Sie keine anderen Einstellungen vornehmen, wird sie im Proxy-Modus ausgeführt. Das heißt, alle asynchronen Methoden, die mit der @Async-Annotation ausgeführt werden, folgen den Einschränkungen von Spring AOP. Für weitere Informationen sieheDiesen Beitrag.


  • Wenn Sie @Async an eine private Methode anhängen, funktioniert AOP nicht.
  • AOP funktioniert nicht, wenn Methoden innerhalb desselben Objekts einander aufrufen.


Quelle

제이온
제이온
제이온
제이온
[Java] Synchronized Collection vs Concurrent Collection Dieser Beitrag analysiert und vergleicht die verschiedenen Methoden und Vor- und Nachteile zur Lösung von Synchronisierungsproblemen bei der Verwendung von Sammlungen in einer Multithread-Umgebung in Java. Es werden die Eigenschaften und Leistungsuntersch

25. April 2024

[Spring] Was sind Filter, Interceptor und Argument Resolver? Erfahren Sie mehr über die Konzepte und Unterschiede von Filtern, Interceptoren und Argument Resolver in Spring-Webanwendungen. Dieser Artikel analysiert die Implementierung, den Zeitpunkt der Verwendung und die Vor- und Nachteile jeder Funktion im Vergle

27. April 2024

[Effektives Java] Artikel 6. Vermeiden Sie unnötige Objekterstellung Dieser Leitfaden behandelt die Vermeidung unnötiger Objekterstellung in Java. Für unveränderliche Objekte wie String und Boolean ist es empfehlenswert, Literale zu verwenden, und für reguläre Ausdrücke sollten Sie Pattern-Instanzen cachen. Auto-Boxing kan

28. April 2024

[Concurrency] Atomarer Vorgang: Memory Fence und Memory Ordering Dieser Blogbeitrag erklärt, wie bei atomaren Operationen die Reihenfolge im Speicher berücksichtigt wird, und die Bedeutung von Ordering-Optionen. Es werden verschiedene Ordering-Optionen wie Relaxed, Acquire, Release, AcqRel, SecCst erläutert und die Vor
곽경직
곽경직
곽경직
곽경직
곽경직

12. April 2024

Wie Rust Konsistenzfehler verhindert Rust ist eine leistungsstarke Sprache, die die Herausforderungen der konkurrenten Programmierung bewältigt. Dank des Typsystems und des Besitzmodells ist der Datenaustausch und die gemeinsame Nutzung zwischen Threads sicher. Durch Muster der internen Vari
곽경직
곽경직
곽경직
곽경직
곽경직

28. März 2024

[Nicht-Hauptfach, Überleben als Entwickler] 14. Zusammenfassung der häufigen technischen Vorstellungsgesprächsinhalte für Einsteiger Dieser Leitfaden ist für die Vorbereitung auf technische Vorstellungsgespräche für Einsteiger. Hauptspeicherbereich, Datenstrukturen, RDBMS und NoSQL, prozedurale und objektorientierte Programmierung, Überladen und Überschreiben, Seitenersatzzustände, Pro
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자

3. April 2024

Schwierigkeiten bei der Entwicklung der 한국투자증권-API Dieser Blog-Post befasst sich ausführlich mit den Schwierigkeiten, die bei der Entwicklung der 한국투자증권-API aufgetreten sind, sowie mit den entsprechenden Lösungen. Er enthält Erfahrungsberichte und Tipps von Entwicklern zu Themen wie Kontoeröffnung, Übertr
(로또 사는 아빠) 살림 하는 엄마
(로또 사는 아빠) 살림 하는 엄마
(로또 사는 아빠) 살림 하는 엄마
(로또 사는 아빠) 살림 하는 엄마
(로또 사는 아빠) 살림 하는 엄마

23. April 2024

[Nicht-Fachmann, Überleben als Entwickler] 16. Tipps für die Erstellung eines Portfolios für Einsteiger Ein Einsteigerentwickler (insbesondere Nicht-Fachmann) muss bei der Erstellung eines Portfolios nicht nur die Technologie, sondern auch die entwickelten Dienste oder Funktionen klar erläutern. Zum Beispiel, wenn es sich um ein "Jobsuchenden-Community"-Pro
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자
투잡뛰는 개발 노동자

3. April 2024

Was ist Slot-Filling? Slot-Filling ist, wenn ein Chatbot wiederholt Fragen stellt, bis er alle notwendigen Informationen vom Benutzer erhalten hat. Zum Beispiel fragt ein Chatbot bei einer Kaffee Bestellung nach der Art, der Temperatur und der Größe, und beendet die Bestellung
꿈많은청년들
꿈많은청년들
Ein Bild mit der Aufschrift "Slot-Filling".
꿈많은청년들
꿈많은청년들

13. Mai 2024