一.異步和同步
異步(async)是相對於同步(sync)來說的,簡單理解,同步是串行的,異步是並行的。
好比說,A需要從B和C兩個節點獲取數據
第一種方式,A請求B,B返回給A數據,A再去請求C,在從C出獲得數據。這種方式就是同步。
另一種方式,A去請求B,不等B返回數據,就去請求C,然後等B和C準備好數據再推送給A,A同樣可以拿到B和C的數據,這就是異步。
注意,第二種方式B和C是同時處理A的請求的,是比第一種方式效率要高的,但是這種方式,有一個限制,就是從B和C之間要獲取的數據不能有依賴關係,假如獲取C的數據時候,C需要從B返回來的數據,那就只能採用第一種方式,先請求B,拿到B的數據,在去請求C。
舉個比較直白的例子,把訂外賣抽象成幾步
- 1.下單,時間忽略不計。
- 2.餐廳做飯,10分鐘。
- 3.找外賣小哥,5分鐘。(這需要一系列很麻煩的算法算出要通知哪些小哥,等小哥接受派送,再計算出大概到達時間,假設5分鐘)
- 4.派送,5分鐘。
按照同步方式處理,1,2,3,4加起來20分鐘時間。
但是餐廳做飯和找外賣小哥嚴格意義上沒有依賴關係,2和3是可以同時進行的,這樣算,就只需要15分鐘。
異步和同步是兩種處理方式,同步適用的場景多,編碼簡單,便於理解,但是在某些特定的場景下異步比同步效率會高出很多。
二.代碼實現,springboot使用異步任務
1.AsyncTaskApplication啓動類添加註解 @EnableAsync // 開啓異步
2.實現任務類,並注入到spring中
package com.frank;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.concurrent.Future;
/**
* @author 小石潭記
* @date 2020/6/29 20:52
* @Description: ${todo}
*/
@Component
public class AsyncTask {
@Async
public Future<String> execTaskA() throws InterruptedException {
System.out.println("TaskA開始");
long star = new Date().getTime();
Thread.sleep(5000);
long end = new Date().getTime();
System.out.println("TaskA結束,耗時毫秒數:" + (end - star));
return new AsyncResult<>("TaskA結束");
}
@Async
public Future<String> execTaskB() throws InterruptedException {
System.out.println("TaskB開始");
long star = new Date().getTime();
Thread.sleep(3000);
long end = new Date().getTime();
System.out.println("TaskB結束,耗時毫秒數:" + (end - star));
return new AsyncResult<>("TaskB結束");
}
@Async
public Future<String> execTaskC() throws InterruptedException {
System.out.println("TaskC開始");
long star = new Date().getTime();
Thread.sleep(4000);
long end = new Date().getTime();
System.out.println("TaskC結束,耗時毫秒數:" + (end - star));
return new AsyncResult<>("TaskC結束");
}
}
3.使用單元測試
package com.frank;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.Date;
import java.util.concurrent.Future;
@SpringBootTest
class AsyncTaskApplicationTests {
@Autowired
AsyncTask asyncTask;
@Test
public void testAsyncTask() throws InterruptedException {
long star = new Date().getTime();
System.out.println("任務開始,當前時間" +star );
Future<String> taskA = asyncTask.execTaskA();
Future<String> taskB = asyncTask.execTaskB();
Future<String> taskC = asyncTask.execTaskC();
//間隔一秒輪詢 直到 A B C 全部完成
while (true) {
if (taskA.isDone() && taskB.isDone() && taskC.isDone()) {
break;
}
Thread.sleep(1000);
}
long end = new Date().getTime();
System.out.println("任務結束,當前時間" + end);
System.out.println("總耗時:"+(end-star));
}
}
通過異步任務,總耗時6031ms
關閉啓動類上的註釋,測試,總耗時12003ms
通過對比,異步總耗時更少。