欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring?框架@Async?注解詳解

 更新時(shí)間:2025年04月26日 09:36:53   作者:java全套學(xué)習(xí)資料  
這篇文章主要介紹了Spring框架@Async注解,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

1.同步調(diào)用與異步調(diào)用

在 Java 中,同步調(diào)用和異步調(diào)用是兩種不同的操作方式,用于處理方法調(diào)用和任務(wù)執(zhí)行。

1.1.同步調(diào)用

(1)定義:同步調(diào)用指的是調(diào)用方法時(shí),調(diào)用者會(huì)等待被調(diào)用的方法執(zhí)行完成后才繼續(xù)執(zhí)行后續(xù)的代碼。也就是說(shuō),方法調(diào)用是阻塞的,當(dāng)前線程會(huì)被阻塞直到方法執(zhí)行結(jié)束并返回結(jié)果。

(2)示例

public class SyncExample {
    public static void main(String[] args) {
        System.out.println("Start");
        //同步調(diào)用
        String result = longRunningTask();
        System.out.println("Result: " + result);
        System.out.println("End");
    }
    public static String longRunningTask() {
        try {
            //模擬長(zhǎng)時(shí)間運(yùn)行的任務(wù)
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "Task Completed";
    }
}

(3)解釋
在上述代碼中,longRunningTask() 方法會(huì)暫停當(dāng)前線程 3 秒鐘,然后返回結(jié)果。在 main 方法中,longRunningTask() 的調(diào)用是同步的,System.out.println("Result: " + result); 會(huì)等待 longRunningTask() 完成后才執(zhí)行。

1.2.異步調(diào)用

(1)定義:異步調(diào)用指的是調(diào)用方法時(shí),調(diào)用者不會(huì)等待方法執(zhí)行完成,而是立即繼續(xù)執(zhí)行后續(xù)的代碼。被調(diào)用的方法在后臺(tái)線程中執(zhí)行,調(diào)用者可以通過(guò)回調(diào)、Future 模式或其他機(jī)制獲取結(jié)果。

(2)示例

import java.util.concurrent.CompletableFuture;
public class AsyncExample {
    public static void main(String[] args) {
        System.out.println("Start");
        //異步調(diào)用
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> longRunningTask());
        //繼續(xù)執(zhí)行其他操作
        System.out.println("Doing other work while waiting for result...");
        //獲取異步任務(wù)的結(jié)果(會(huì)阻塞,直到任務(wù)完成)
        future.thenAccept(result -> System.out.println("Result: " + result));
        System.out.println("End");
    }
    public static String longRunningTask() {
        try {
            //模擬長(zhǎng)時(shí)間運(yùn)行的任務(wù)
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "Task Completed";
    }
}

(3)解釋:在上述代碼中,longRunningTask() 被異步執(zhí)行,通過(guò) CompletableFuture.supplyAsync 方法。在異步執(zhí)行期間,System.out.println("Doing other work while waiting for result..."); 會(huì)繼續(xù)執(zhí)行,不會(huì)被阻塞。future.thenAccept(result -> System.out.println("Result: " + result)); 會(huì)在任務(wù)完成后處理結(jié)果。

1.3.總結(jié)

  • 同步調(diào)用
    • 特點(diǎn):調(diào)用方在發(fā)起方法調(diào)用后,必須等待被調(diào)用的方法完成并返回結(jié)果之后,才能繼續(xù)執(zhí)行后續(xù)的操作(即會(huì)阻塞)。在同步調(diào)用中,調(diào)用方和被調(diào)用方的執(zhí)行順序是嚴(yán)格按照調(diào)用順序進(jìn)行的。
    • 適用場(chǎng)景:
      • 依賴順序:當(dāng)某個(gè)操作必須在另一個(gè)操作完成后才能進(jìn)行時(shí)。
      • 簡(jiǎn)單任務(wù):當(dāng)任務(wù)執(zhí)行時(shí)間短且沒(méi)有并發(fā)問(wèn)題時(shí)。
      • 確保執(zhí)行順序:需要確保多個(gè)步驟按順序完成,比如數(shù)據(jù)庫(kù)事務(wù)處理。
  • 異步調(diào)用
    • 特點(diǎn):調(diào)用方發(fā)起方法調(diào)用后,不必等待被調(diào)用的方法完成,而是可以繼續(xù)執(zhí)行后續(xù)的操作。被調(diào)用的方法將在后臺(tái)線程中運(yùn)行,完成后會(huì)通知調(diào)用方結(jié)果或執(zhí)行回調(diào)。
    • 適用場(chǎng)景:
      • 任務(wù)需要較長(zhǎng)時(shí)間完成,阻塞主線程會(huì)影響程序的響應(yīng)性。
      • 需要處理多個(gè)任務(wù)時(shí),通過(guò)異步調(diào)用可以提高并發(fā)處理能力。
      • 用戶界面應(yīng)用中,異步操作可以防止界面凍結(jié),提升用戶體驗(yàn)。

2.注解 @Async 介紹

@Async 注解中的 Async 是單詞 Asynchronous 的縮寫(xiě)。Asynchronous 指的是“異步的”,即操作或方法的執(zhí)行不會(huì)阻塞當(dāng)前線程,允許在后臺(tái)執(zhí)行任務(wù)的同時(shí)繼續(xù)進(jìn)行其他操作。使用 @Async 注解可以讓 Spring 在后臺(tái)線程池中異步執(zhí)行被注解的方法,從而提升應(yīng)用的性能和響應(yīng)能力。@Async 注解的代碼如下所示:

package org.springframework.scheduling.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.aot.hint.annotation.Reflective;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Reflective
public @interface Async {
    String value() default "";
}

@Async 注解用在方法和類上的作用分別如下:

2.1.用在方法上

(1)功能:標(biāo)記方法為異步執(zhí)行,這意味著方法將在一個(gè)新的線程中執(zhí)行,不會(huì)阻塞調(diào)用該方法的線程。并且方法所在的類必須要被 Spring 作為 Bean 管理。
(2)限制:只對(duì) public 方法有效,且方法返回類型為 void 或者 Future。
(3)例子:

@Async
public CompletableFuture<String> asyncMethod() {
    // 執(zhí)行異步任務(wù)
}

2.2.用在類上

(1)功能:標(biāo)記類中的所有 public 方法都為異步執(zhí)行。這個(gè)類必須要被 Spring 作為 Bean 管理,并且所有被 @Async 注解的方法都會(huì)異步執(zhí)行。
(2)限制:類上使用 @Async 不一定能保證類中所有方法都異步執(zhí)行,特別是如果方法被類內(nèi)部直接調(diào)用時(shí),例如方法 asyncMethod2 在同一類內(nèi)直接調(diào)用方法 asyncMethod1,asyncMethod1 會(huì)在當(dāng)前線程中同步執(zhí)行,而不是異步執(zhí)行。
(3)例子:

@Async
@Service
public class MyService {
    public CompletableFuture<String> asyncMethod1() {
        // 執(zhí)行異步任務(wù)
    }
    public CompletableFuture<String> asyncMethod2() {
        // 執(zhí)行異步任務(wù)
    }
}

3.使用演示

一般來(lái)說(shuō),@Async 注解用在方法上來(lái)指定特定方法異步執(zhí)行,標(biāo)記整個(gè)類的方式較少使用。

3.1.在啟動(dòng)類或者配置類上增加 @EnableAsync 注解

例如,在 Spring Boot 項(xiàng)目的啟動(dòng)類上增加 @EnableAsync 注解:

@EnableAsync	//開(kāi)啟異步調(diào)用
@SpringBootApplication
public class MyExampleApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyExampleApplication.class, args);
    }
}

@EnableAsync 注解用于啟用 Spring 框架的異步方法執(zhí)行功能。它使得應(yīng)用程序能夠處理被 @Async 注解標(biāo)記的方法,確保這些方法在獨(dú)立的線程中異步執(zhí)行。將 @EnableAsync 注解添加到配置類或者啟動(dòng)類上后,Spring 將自動(dòng)配置所需的支持,并允許 @Async 注解在應(yīng)用程序中生效。

3.2.在異步方法上增加 @Async 注解

package com.example.myexample.service.async;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
@Slf4j
@Service
public class MyAsyncTask {
    @Async
    public void notifyUser() {
        log.info("asyncTask 方法所處的線程:{}", Thread.currentThread().getName());
        //模擬處理異步任務(wù)
        try {
            Thread.sleep(3000);
            log.info("通知用戶保存訂單成功");
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

3.3.調(diào)用異步方法

package com.example.myexample.controller;
import com.example.myexample.service.OrderService;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
@RequestMapping("asyncTest")
public class AsyncTestController {
    @Resource
    private OrderService orderService;
    @PostMapping
    public String saveOrder() {
        orderService.saveOrder();
        return "success";
    }
}
package com.example.myexample.service;
public interface OrderService {
    void saveOrder();
}
package com.example.myexample.service.impl;
import com.example.myexample.service.OrderService;
import com.example.myexample.service.async.MyAsyncTask;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Slf4j
@Service
public class OrderServiceImpl implements OrderService {
    @Resource
    private MyAsyncTask myAsyncTask;
    @Override
    public void saveOrder() {
        log.info("saveOrder 方法所處的線程:{}", Thread.currentThread().getName());
        log.info("保存訂單");
        //調(diào)用異步方法
        myAsyncTask.notifyUser();
        postProcess();
    }
	public void postProcess() {
        log.info("postProcess 方法所處的線程:{}", Thread.currentThread().getName());
    }
}

上述代碼只包括了調(diào)用異步方法的核心部分,其它部分代碼(例如 Controller 層)并未給出。

3.4.測(cè)試

使用 Postman 進(jìn)行測(cè)試:

http://localhost:8080/asyncTest/

日志打印結(jié)果如下,從中可以發(fā)現(xiàn):方法 saveOrdernotifyUser 在不同的線程中執(zhí)行了,即 notifyUser 確實(shí)被異步調(diào)用了。

3.5.其它說(shuō)明

如果要將異步方法改為有返回值,可以將返回類型從 void 改為 Future<T>CompletableFuture<T>。這里我們使用 CompletableFuture 作為返回類型:

@Async
public CompletableFuture<String> notifyUser2() {
    log.info("asyncTask 方法所處的線程:{}", Thread.currentThread().getName());
    // 模擬處理異步任務(wù)
    try {
        Thread.sleep(3000);
        log.info("通知用戶保存訂單成功");
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
    return CompletableFuture.completedFuture("通知用戶保存訂單成功");
}
public void saveOrder2() {
    log.info("saveOrder 方法所處的線程:{}", Thread.currentThread().getName());
    log.info("保存訂單");
    CompletableFuture<String> future = myAsyncTask.notifyUser2();
    //在需要時(shí)可以調(diào)用 get() 來(lái)阻塞當(dāng)前線程直到異步任務(wù)完成
    try {
        String result = future.get(); // 這將阻塞直到異步任務(wù)完成
        System.out.println("任務(wù)結(jié)果: " + result);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

有關(guān) Future 模式的相關(guān)知識(shí)可以參考 Java 并發(fā)編程面試題——Future 模式這篇文章。

4.注意事項(xiàng)

4.1.@Async 注解失效的常見(jiàn)情況

@Async 注解在某些情況下可能會(huì)失效,包括:

  • 方法定義不符合要求@Async 方法必須是 public,并且不能是 final、staticprivate。
  • 類未被 Spring 掃描:確保含有 @Async 注解的類被 Spring 掃描到。通常需要將類放在 @Component、@Service 或其他 Spring 管理的組件中。
  • 缺少 @EnableAsync 注解:在配置類上未添加 @EnableAsync 注解,Spring 不會(huì)啟用異步處理。
  • 方法調(diào)用在同一類內(nèi)部@Async 方法被同一類的其他方法調(diào)用時(shí)不會(huì)生效,因?yàn)?Spring 的代理機(jī)制無(wú)法處理同一類內(nèi)的調(diào)用。
  • 返回值處理不當(dāng):異步方法通常返回 Futurevoid,確保返回值類型正確處理。

4.2.使用 @Async 注解可能會(huì)導(dǎo)致循環(huán)依賴

4.2.1.示例

需要注意的是,如果代碼編寫(xiě)不當(dāng),在使用 @Async 注解可能會(huì)導(dǎo)致循環(huán)依賴,例如:

@Service
public class CDTestsService1Impl implements CDTestsService1 {
    @Autowired
    private CDTestsService2 cdTestsService2;
    @Async
    @Override
    public void performAsyncTask() {
        System.out.println("performAsyncTask...");
    }
}
@Service
public class CDTestsService2Impl implements CDTestsService2 {
    @Autowired
    private CDTestsService1 cdTestsService1;
    @Override
    public void performTask() {
        cdTestsService1.performAsyncTask();
    }
}
@RestController
@RequestMapping("asyncTest")
public class AsyncTestController {
    @Resource
    private CDTestsService2 cdTestsService2;
    @PostMapping("/cdTest")
    public String cdTest() {
        cdTestsService2.performTask();
        return "success";
    }
}

當(dāng)啟動(dòng)項(xiàng)目時(shí),會(huì)出現(xiàn)循環(huán)依賴的異常提示:

4.2.2.原因分析

循環(huán)依賴:

  • CDTestsService1Impl 依賴于 CDTestsService2Impl,并且 CDTestsService2Impl 依賴于 CDTestsService1Impl。這種相互依賴會(huì)導(dǎo)致 Spring 容器在創(chuàng)建這些 bean 時(shí)發(fā)生問(wèn)題。
  • 當(dāng) Spring 容器創(chuàng)建 CDTestsService1Impl 時(shí),它需要注入 CDTestsService2Impl。接著,創(chuàng)建 CDTestsService2Impl 時(shí),它需要注入 CDTestsService1Impl。這樣,就會(huì)形成一個(gè)死循環(huán),因?yàn)閮蓚€(gè) bean 互相等待對(duì)方被完全創(chuàng)建和注入。

@Async 注解的影響:

  • @Async 注解用于異步執(zhí)行方法。這意味著 performAsyncTask 方法會(huì)在不同的線程中運(yùn)行,因此不會(huì)阻塞當(dāng)前線程。但是,Spring 在執(zhí)行異步方法時(shí),仍然需要確保異步方法的 bean 實(shí)例在調(diào)用之前已完全創(chuàng)建和注入。
  • 由于 performAsyncTask 是異步的,Spring 在調(diào)用這個(gè)方法時(shí)可能會(huì)遇到由于循環(huán)依賴未完全解決而引發(fā)的異常。

4.2.3.解決方案

(1)使用構(gòu)造函數(shù)注入
使用構(gòu)造函數(shù)注入可以避免循環(huán)依賴問(wèn)題。構(gòu)造函數(shù)注入在 bean 創(chuàng)建時(shí)確保所有依賴項(xiàng)都已解決,因此更可靠。

@Service
public class CDTestsService1Impl implements CDTestsService1 {
    private final CDTestsService2 cdTestsService2;
    @Autowired
    public CDTestsService1Impl(CDTestsService2 cdTestsService2) {
        this.cdTestsService2 = cdTestsService2;
    }
    @Async
    @Override
    public void performAsyncTask() {
        System.out.println("performAsyncTask...");
    }
}
@Service
public class CDTestsService2Impl implements CDTestsService2 {
    private final CDTestsService1 cdTestsService1;
    @Autowired
    public CDTestsService2Impl(CDTestsService1 cdTestsService1) {
        this.cdTestsService1 = cdTestsService1;
    }
    @Override
    public void performTask() {
        cdTestsService1.performAsyncTask();
    }
}

(2)使用 @Lazy 注解
@Lazy 注解可以推遲 bean 的初始化,解決循環(huán)依賴問(wèn)題。你可以將 @Lazy 注解添加到字段注入中,以便在需要時(shí)才加載依賴。

@Service
public class CDTestsService1Impl implements CDTestsService1 {
    @Autowired
    @Lazy
    private CDTestsService2 cdTestsService2;
    @Async
    @Override
    public void performAsyncTask() {
        System.out.println("performAsyncTask...");
    }
}
@Service
public class CDTestsService2Impl implements CDTestsService2 {
    @Autowired
    @Lazy
    private CDTestsService1 cdTestsService1;
    @Override
    public void performTask() {
        cdTestsService1.performAsyncTask();
    }
}

(3)分離異步調(diào)用
如果 performAsyncTask 不需要立即執(zhí)行,考慮將它移到另一個(gè)服務(wù)中,或通過(guò)其他機(jī)制避免直接的循環(huán)依賴。

@Service
public class CDTestsService1Impl implements CDTestsService1 {
    @Autowired
    private TaskExecutor taskExecutor;  // Spring 提供的 TaskExecutor
    @Override
    public void performAsyncTask() {
        taskExecutor.execute(() -> {
            System.out.println("performAsyncTask...");
        });
    }
}
@Service
public class CDTestsService2Impl implements CDTestsService2 {
    @Autowired
    private CDTestsService1 cdTestsService1;
    @Override
    public void performTask() {
        cdTestsService1.performAsyncTask();
    }
}

使用 TaskExecutor 來(lái)執(zhí)行異步任務(wù)可以將異步執(zhí)行的邏輯與服務(wù)依賴解耦,避免直接在服務(wù)之間形成循環(huán)依賴。

到此這篇關(guān)于Spring 框架@Async 注解的文章就介紹到這了,更多相關(guān)Spring  @Async 注解內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java實(shí)現(xiàn)簡(jiǎn)單學(xué)生管理系統(tǒng)項(xiàng)目

    java實(shí)現(xiàn)簡(jiǎn)單學(xué)生管理系統(tǒng)項(xiàng)目

    這篇文章主要介紹了java實(shí)現(xiàn)簡(jiǎn)單學(xué)生管理系統(tǒng)項(xiàng)目,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-07-07
  • Spring Boot 靜態(tài)資源處理

    Spring Boot 靜態(tài)資源處理

    今天小編就為大家分享一篇關(guān)于Spring Boot 靜態(tài)資源處理,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2018-12-12
  • MyBatis-plus如何執(zhí)行自定義SQL

    MyBatis-plus如何執(zhí)行自定義SQL

    這篇文章主要介紹了MyBatis-plus如何執(zhí)行自定義SQL問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-02-02
  • java基礎(chǔ)之NIO介紹及使用

    java基礎(chǔ)之NIO介紹及使用

    這篇文章主要介紹了java基礎(chǔ)之NIO介紹及使用,文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)java基礎(chǔ)的小伙伴們有非常好的幫助,需要的朋友可以參考下
    2021-04-04
  • java實(shí)現(xiàn)MD5加密方法匯總

    java實(shí)現(xiàn)MD5加密方法匯總

    本文給大家匯總介紹了2種java實(shí)現(xiàn)MD5加密的方法,非常的實(shí)用,這里分享給大家,學(xué)習(xí)下其中的思路,對(duì)大家學(xué)習(xí)java非常有幫助。
    2015-10-10
  • Java中static的特點(diǎn)

    Java中static的特點(diǎn)

    本文主要介紹了Java中static的特點(diǎn)。具有很好的參考價(jià)值。下面跟著小編一起來(lái)看下吧
    2017-03-03
  • 淺談spring使用策略模式實(shí)現(xiàn)多種場(chǎng)景登錄方式

    淺談spring使用策略模式實(shí)現(xiàn)多種場(chǎng)景登錄方式

    本文主要介紹了spring使用策略模式實(shí)現(xiàn)多種場(chǎng)景登錄方式,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-12-12
  • 利用Java讀取二進(jìn)制文件實(shí)例詳解

    利用Java讀取二進(jìn)制文件實(shí)例詳解

    這篇文章主要給大家介紹了利用Java讀取二進(jìn)制文件的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者使用java具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面跟著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-08-08
  • 實(shí)例講解Java中的synchronized

    實(shí)例講解Java中的synchronized

    這篇文章主要介紹了Java中synchronized的使用方法,文中講解非常細(xì)致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-07-07
  • java實(shí)現(xiàn)對(duì)map的字典序排序操作示例

    java實(shí)現(xiàn)對(duì)map的字典序排序操作示例

    這篇文章主要介紹了java實(shí)現(xiàn)對(duì)map的字典序排序操作,結(jié)合實(shí)例形式分析了java參照微信官網(wǎng)算法實(shí)現(xiàn)的字典序排序操作相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2019-07-07

最新評(píng)論