您當前的位置:首頁 > 詩詞

面試官:java8中parallelStream提升數倍查詢效率是怎樣實現的

作者:由 該使用者快成仙了 發表于 詩詞時間:2020-08-05

業務場景

在很多專案中,都有類似資料彙總的業務場景,查詢今日註冊會員數,線上會員數,訂單總金額,支出總金額等。。。這些業務通常都不是存在同一張表中,我們需要依次查詢出來然後封裝成所需要的物件返回給前端。那麼在此過程中,就可以把這個介面中“大任務”拆分成N個小任務,非同步執行這些小任務,等到最後一個小任務執行完,把所有任務的執行結果封裝到返回結果中,統一返回到前端展示。

面試官:java8中parallelStream提升數倍查詢效率是怎樣實現的

同步執行

首先看看同步執行的程式碼

public class Test {

@Data

@NoArgsConstructor

@AllArgsConstructor

@ToString

class Result {

/**

* 線上人數

*/

Integer onlineUser;

/**

* 註冊人數

*/

Integer registered;

/**

* 訂單總額

*/

BigDecimal orderAmount;

/**

* 支出總額

*/

BigDecimal outlayAmount;

}

@org。junit。Test

public void collect() {

System。out。println(“資料彙總開始”);

long startTime = System。currentTimeMillis();

Integer onlineUser = queryOnlineUser();

Integer registered = queryRegistered();

BigDecimal orderAmount = queryOrderAmount();

BigDecimal outlayAmount = queryOutlayAmount();

Result result = new Result(onlineUser, registered, orderAmount, outlayAmount);

long endTime = System。currentTimeMillis();

System。out。println(“獲取彙總資料結束,result = ” + result);

System。out。println(“總耗時 = ” + (endTime - startTime) + “毫秒”);

}

public Integer queryOnlineUser() {

try {

Thread。sleep(2000);

} catch (InterruptedException e) {

e。printStackTrace();

}

System。out。println(“查詢線上人數 耗時2秒”);

return 10;

}

public Integer queryRegistered() {

try {

Thread。sleep(2000);

} catch (InterruptedException e) {

e。printStackTrace();

}

System。out。println(“查詢註冊人數 耗時2秒”);

return 10086;

}

public BigDecimal queryOrderAmount() {

try {

Thread。sleep(3000);

} catch (InterruptedException e) {

e。printStackTrace();

}

System。out。println(“查詢訂單總額 耗時3秒”);

return BigDecimal。valueOf(2000);

}

public BigDecimal queryOutlayAmount() {

try {

Thread。sleep(3000);

} catch (InterruptedException e) {

e。printStackTrace();

}

System。out。println(“查詢支出總額 耗時3秒”);

return BigDecimal。valueOf(1000);

}

}

執行時長想必大家都能夠想得到,理所應當是10秒以上

資料彙總開始

查詢線上人數 耗時2秒

查詢註冊人數 耗時2秒

查詢訂單總額 耗時3秒

查詢支出總額 耗時3秒

獲取彙總資料結束,result = Test。Result(onlineUser=10, registered=10086, orderAmount=2000, outlayAmount=1000)

總耗時 = 10008毫秒

面試官:java8中parallelStream提升數倍查詢效率是怎樣實現的

非同步執行

下面換成非同步執行,用java8的parallelStream(並行流),這裡為什麼不用Thread呢,這裡有一個注意點,我們需要獲取所有所有子任務執行完的時間點,在這個時間點之後才能將結果封裝返回,Thread沒有辦法滿足,這裡parallelStream和函式式介面就登場了。

java8的特性之一 —— lambda表示式,就是配合函式式介面使用的。

java8內建了四大核心函式式介面:

1、Consumer : 消費型介面 void accept(T t);

2、Supplier : 供給型介面 T get();

3、Function : 函式型介面 R apply(T t);

4、Predicate : 斷言型介面 boolean test(T t);

這四大核心函式式介面其下還有很多子介面,基本上能滿足日常專案所用,這裡扯遠了。。 直接上程式碼。

這裡我們需要使用的是Runable介面,是無參無返回值的一個介面。在實際場景中,可能有時間範圍之類的查詢引數的,則可以根據不同業務使用不同的介面。這種方式也可以用Future介面去實現,有興趣的可以試一試,這裡就不多做敘述了。

@org。junit。Test

public void collect() {

System。out。println(“資料彙總開始”);

long startTime = System。currentTimeMillis();

Result result = new Result();

List taskList = new ArrayList() {

{

add(() -> result。setOnlineUser(queryOnlineUser()));

add(() -> result。setRegistered(queryRegistered()));

add(() -> result。setOrderAmount(queryOrderAmount()));

add(() -> result。setOutlayAmount(queryOutlayAmount()));

}

};

taskList。parallelStream()。forEach(v -> v。run());

long endTime = System。currentTimeMillis();

System。out。println(“獲取彙總資料結束,result = ” + result);

System。out。println(“總耗時 = ” + (endTime - startTime) + “毫秒”);

}

執行結果,由於四個子任務都是並行的,效率直接提升了三倍,如果子任務越多的話提升效果越明顯。

資料彙總開始

查詢線上人數 耗時2秒

查詢註冊人數 耗時2秒

查詢訂單總額 耗時3秒

查詢支出總額 耗時3秒

獲取彙總資料結束,result = Test。Result(onlineUser=10, registered=10086, orderAmount=2000, outlayAmount=1000)

總耗時 = 3079毫秒

總結

1。parallelStream是非同步程式設計的好幫手,在使用過程中一定要注意執行緒安全的問題。

2。以上這種方式只能用在沒有事務的業務中,因為在多執行緒中,事務是不共享的。

面試官:java8中parallelStream提升數倍查詢效率是怎樣實現的

標簽: System  耗時  Result  介面  查詢