1. 程式人生 > >Spring @Async實現非同步呼叫示例

Spring @Async實現非同步呼叫示例

什麼是非同步呼叫

       “非同步呼叫”對應的是“同步呼叫”,同步呼叫指程式按照定義順序依次執行,每一行程式都必須等待上一行程式執行完成之後才能執行;非同步呼叫指程式在順序執行時,不等待非同步呼叫的語句返回結果就執行後面的程式。

同步呼叫

下面通過一個簡單示例來直觀的理解什麼是同步呼叫:

       定義Task類,建立三個處理函式分別模擬三個執行任務的操作,操作消耗時間隨機取(10秒內)

package com.dxz.demo1;

import java.util.Random;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping; /** * 定義3個任務 */ @Component public class Task1 { // 定義一個隨機物件. public static Random random = new Random(); // 任務一; public void doTaskOne() throws Exception { System.out.println("開始做任務一"); long
start = System.currentTimeMillis(); Thread.sleep(random.nextInt(10000)); long end = System.currentTimeMillis(); System.out.println("完成任務一,耗時:" + (end - start) + "毫秒"); } // 任務二; public void doTaskTwo() throws Exception { System.out.println("開始做任務二");
long start = System.currentTimeMillis(); Thread.sleep(random.nextInt(10000)); long end = System.currentTimeMillis(); System.out.println("完成任務二,耗時:" + (end - start) + "毫秒"); } // 任務3; public void doTaskThree() throws Exception { System.out.println("開始做任務三"); long start = System.currentTimeMillis(); Thread.sleep(random.nextInt(10000)); long end = System.currentTimeMillis(); System.out.println("完成任務三,耗時:" + (end - start) + "毫秒"); } }

編寫一個訪問方法:

package com.dxz.demo1;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.dxz.HelloApplication;

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = HelloApplication.class)
public class Task1Test {

    @Autowired
    private Task1 task1;
    
    //測試task1.
    @Test
    public void task1() throws Exception{
       task1.doTaskOne();
       task1.doTaskTwo();
       task1.doTaskThree();
    }
}

執行可以看到類似如下輸出:

開始做任務一
2017-04-28 18:02:57.397  WARN 11016 --- [cTaskExecutor-1] o.s.a.r.l.SimpleMessageListenerContainer : Consumer raised exception, processing can restart if the connection factory supports it. Exception summary: org.springframework.amqp.AmqpConnectException: java.net.ConnectException: Connection refused: connect
2017-04-28 18:02:57.398  INFO 11016 --- [cTaskExecutor-1] o.s.a.r.l.SimpleMessageListenerContainer : Restarting Consumer: tags=[{}], channel=null, acknowledgeMode=AUTO local queue size=0
完成任務一,耗時:7740毫秒
開始做任務二
完成任務二,耗時:723毫秒
開始做任務三
2017-04-28 18:03:03.415  WARN 11016 --- [cTaskExecutor-2] o.s.a.r.l.SimpleMessageListenerContainer : Consumer raised exception, processing can restart if the connection factory supports it. Exception summary: org.springframework.amqp.AmqpConnectException: java.net.ConnectException: Connection refused: connect
2017-04-28 18:03:03.415  INFO 11016 --- [cTaskExecutor-2] o.s.a.r.l.SimpleMessageListenerContainer : Restarting Consumer: tags=[{}], channel=null, acknowledgeMode=AUTO local queue size=0
完成任務三,耗時:5047毫秒

非同步呼叫

上述的同步呼叫雖然順利的執行完了三個任務,但是可以看到執行時間比較長,若這三個任務本身之間不存在依賴關係,可以併發執行的話,同步呼叫在執行效率方面就比較差,可以考慮通過非同步呼叫的方式來併發執行。

在Spring Boot中,我們只需要通過使用@Async註解就能簡單的將原來的同步函式變為非同步函式,Task類改在為如下模式:

package com.dxz.demo1;

import java.util.Random;

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * 定義3個任務
 */
@Component
public class Task2 {
    
    // 定義一個隨機物件.
    public static Random random = new Random();

    // 任務一;
    @Async
    public void doTaskOne() throws Exception {
        System.out.println("開始做任務一");
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        System.out.println("完成任務一,耗時:" + (end - start) + "毫秒");
    }

    // 任務二;
    @Async
    public void doTaskTwo() throws Exception {
        System.out.println("開始做任務二");
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        System.out.println("完成任務二,耗時:" + (end - start) + "毫秒");
    }

    // 任務3;
    @Async
    public void doTaskThree() throws Exception {
        System.out.println("開始做任務三");
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        System.out.println("完成任務三,耗時:" + (end - start) + "毫秒");
    }
    

}

  為了讓@Async註解能夠生效,還需要在Spring Boot的主程式中配置@EnableAsync,如下所示:

package com.dxz;

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

編寫測試方法:

package com.dxz.demo1;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.web.bind.annotation.RequestMapping;

import com.dxz.HelloApplication;

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = HelloApplication.class)
public class Task2Test {

    @Autowired
    private Task2 task2;
    
    //測試task1.
    @Test
    public void task1() throws Exception{
       task2.doTaskOne();
       task2.doTaskTwo();
       task2.doTaskThree();
    }
}

此時可以反覆執行單元測試,您可能會遇到各種不同的結果,比如:

開始做任務一
開始做任務二
開始做任務三

修改下測試類:

package com.dxz.demo1;

import java.util.concurrent.TimeUnit;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.web.bind.annotation.RequestMapping;

import com.dxz.HelloApplication;

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = HelloApplication.class)
public class Task2Test {

    @Autowired
    private Task2 task2;

    // 測試task1.
    @Test
    public void task1() throws Exception {
        task2.doTaskOne();
        task2.doTaskTwo();
        task2.doTaskThree();

        System.out.println("i'm here");
        TimeUnit.SECONDS.sleep(15);
        System.out.println("over");
    }

}

 jieguo:

i'm here
開始做任務二
開始做任務一
開始做任務三
完成任務三,耗時:1280毫秒
2017-04-28 18:25:36.936 WARN 17848 --- [cTaskExecutor-1] o.s.a.r.l.SimpleMessageListenerContainer : Consumer raised exception, processing can restart if the connection factory supports it. Exception summary: org.springframework.amqp.AmqpConnectException: java.net.ConnectException: Connection refused: connect
2017-04-28 18:25:36.938 INFO 17848 --- [cTaskExecutor-1] o.s.a.r.l.SimpleMessageListenerContainer : Restarting Consumer: tags=[{}], channel=null, acknowledgeMode=AUTO local queue size=0
完成任務一,耗時:4951毫秒
完成任務二,耗時:7451毫秒
2017-04-28 18:25:42.971 WARN 17848 --- [cTaskExecutor-2] o.s.a.r.l.SimpleMessageListenerContainer : Consumer raised exception, processing can restart if the connection factory supports it. Exception summary: org.springframework.amqp.AmqpConnectException: java.net.ConnectException: Connection refused: connect
2017-04-28 18:25:42.972 INFO 17848 --- [cTaskExecutor-2] o.s.a.r.l.SimpleMessageListenerContainer : Restarting Consumer: tags=[{}], channel=null, acknowledgeMode=AUTO local queue size=0
over

相關推薦

Spring @Async實現非同步呼叫示例

什麼是“非同步呼叫”?        “非同步呼叫”對應的是“同步呼叫”,同步呼叫指程式按照定義順序依次執行,每一行程式都必須等待上一行程式執行完成之後才能執行;非同步呼叫指程式在順序執行時,不等待非同步呼叫的語句返回結果就執行後面的程式。 同步呼叫 下面通過一個簡單示例來直觀的理解什麼是同步呼叫:

Spring Boot2.0之@Async實現非同步呼叫

 補充一個知識點: lombok底層原理使用的是: 位元組碼技術ASM修改位元組碼檔案,生成比如類似於get() set( )方法 一定要在開發工具安裝 在編譯時候修改位元組碼檔案(底層使用位元組碼技術),線上環境使用編譯好的檔案   下面我們學習 Spring Boot 非同步呼

Spring Boot 基礎系列教程 | 第三十二篇:使用@Async實現非同步呼叫:自定義執行緒池

推薦 Spring Boot/Cloud 視訊: 在之前的Spring Boot基礎教程系列中,已經通過《Spring Boot中使用@Async實現非同步呼叫》一文介紹過如何使用@Async註解來實現非同步呼叫了。但是,對於這些非同步執行的控制是我們保障自身

Spring Boot中使用@Async實現非同步呼叫

一 點睛 1 什麼是“非同步呼叫” “非同步呼叫”對應的是“同步呼叫”,同步呼叫指程式按照定義順序依次執行,每一行程式都必須等待上一行程式執行完成之後才能執行;非同步呼叫指程式在順序執行時,不等待非

Spring Boot學習(十二)之Spring Boot使用@Async實現非同步呼叫

什麼是“非同步呼叫”?“非同步呼叫”對應的是“同步呼叫”,同步呼叫指程式按照定義順序依次執行,每一行程式都必須等待上一行程式執行完成之後才能執行;非同步呼叫指程式在順序執行時,不等待非同步呼叫的語句返回

Spring Boot使用@Async實現非同步呼叫返回結果:使用Future以及定義超時

關於使用 @Async實現非同步呼叫的內容,也得到不少童鞋的反饋,其中問題比較多的就是關於返回 Future的使用方法以及對非同步執行的超時控制,所以這篇就來一起講講這兩個問題的處理。 如果您對於 @Async註解的使用還不瞭解的話,可以看看之前的文章,具體如下: 定

springboot乾貨——(十六)使用@Async實現非同步呼叫

非同步呼叫針對的是同步呼叫,一般在程式碼中我們使用同步呼叫相對較多,即請求程式碼立即返回結果或者說執行程式碼,非同步呼叫則是指請求之後不會裡面返回結果或者是呼叫程式碼。 接下來我們用例項來看下什麼是同步呼叫: 新建一個springboot專案後建立對應的task類: pa

SpringBoot之——使用@Async實現非同步呼叫

一、什麼是“非同步呼叫”“非同步呼叫”對應的是“同步呼叫”,同步呼叫指程式按照定義順序依次執行,每一行程式都必須等待上一行程式執行完成之後才能執行;非同步呼叫指程式在順序執行時,不等待非同步呼叫的語句返回結果就執行後面的程式。二、同步呼叫下面通過一個簡單示例來直觀的理解什麼是

如何運用Spring框架的@Async實現非同步任務

在此篇文章中,我們根據使用@Async註解進行探索Spring對非同步執行的支援。簡單的把@As

Spring boot ApplicationEvent實現非同步呼叫

1.什麼是事件機制 事件機制在java的設計模式中也可以叫監聽器模式或者是觀察者模式。 當有事件發生時,通知關注次事件的物件傳送訊息,告訴它有一個事件發生了,那麼怎麼知道通知誰呢? 那必須要在對這個事件感興趣的物件中定義這個事件,一旦有事件發生了,對事件有興

譯文:如何運用Spring框架的@Async實現非同步任務

概要說明 在此篇文章中,我們根據使用@Async註解進行探索Spring對非同步執行的支援。 簡單的把@Async註解放到Bean的方法上就會使用不同的執行緒執行,也就是說,呼叫者執行此方法不用一直等待整個方法執行完畢。 在Spring中比較有趣的一點就是

spring使用Async實現非同步或者延遲的操作

對於我們的web專案,一般來說,我們都是同步執行一些資料,所謂同步就是按照順序,執行完這個然後有序的執行下一個,但是有時我們需要延遲執行一些資料,並且這些資料我們不需要實時的返回的,比如是註冊成功,我們會返回一封郵件給使用者,這個郵件我們可以在使用者註冊成功後的5分鐘,或者10分鐘後向使用者傳送,那麼我們就

java實現非同步呼叫例項

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

spring+mq實現非同步處理

最近研究了一下spring/spring boot與activeMq的整合,花費了很多時間,也遇到了很多坑,工作之餘,總結一下。 業務邏輯是這樣的,有一個功能(比如使用者註冊)執行十分緩慢,但是實際需要發起請求之後馬上提示“處理成功”而不關心是否真的處理成功,這種情況就可以交給MQ來處理

Java 實現非同步呼叫

首先 我遇到的問題是 介面呼叫時需要更新快取 而更新快取又是個說快不快的過程 所以打算做非同步呼叫 返回我所需要的結果即可 ,至於快取什麼時候更新完 就不是我所需要關注的了廢話不多說 上程式碼public class MyExecutor {    private Execu

Java多執行緒實現非同步呼叫

在JAVA平臺,實現非同步呼叫的角色有如下三個角色:呼叫者 提貨單   真實資料 一個呼叫者在呼叫耗時操作,不能立即返回資料時,先返回一個提貨單.然後在過一斷時間後憑提貨單來獲取真正的資料. 去蛋糕店買蛋糕,不需要等蛋糕做出來(假設現做要很長時間),只需要領個提貨單就可以了(去幹別的事情),等到蛋糕做好

使用 RabbitMQ 實現非同步呼叫

目錄 引言 啟動 RabbitMQ 伺服器 執行 rabbitmq 容器 RabbitMQ 控制檯 Exchange 和 Queue 開發服務端和客戶端 開發服務端 開發客戶端 Java Bean 型別傳輸 結語

c#使用委託實現非同步呼叫

非同步程式設計是受公共語言執行庫的許多領域(如遠端處理、ASP.NET 和 Windows 窗體)支援的功能。非同步程式設計是 .NET Framework 中的核心概念。使用 .NET 非同步程式設計,在程式繼續執行的同時對 .NET 類方法進行呼叫,直到進行指定的回撥為止

從Java future 到 Guava ListenableFuture實現非同步呼叫

前言      隨著移動網際網路的蓬勃發展,手機App層出不窮,其業務也隨之變得錯綜複雜。針對於開發人員來說,可能之前的一個業務只需要調取一次第三方介面以獲取資料,而如今隨著需求的增加,該業務需調取多個不同的第三方介面。通常,我們處理方法是讓程式碼

CXF整合spring框架實現動態呼叫,找不到函式介面, 新增攔截器無法初始化

介面實現 新增targetNamespace客戶端就不會找不到函式 @WebService(endpointInterface="cn.com.wsws.server.SealService",se