前面我們提到線程池處理批量接口請(qǐng)求實(shí)踐但是在語(yǔ)法上比較復(fù)雜,還需要進(jìn)行線程間的同步,也需要一定的Java知識(shí),最近在學(xué)習(xí)Golang語(yǔ)言時(shí),感覺(jué)go關(guān)鍵字十分高效,只要是想異步執(zhí)行的方法,只需在前面添加go關(guān)鍵字即可。
如果Java也能實(shí)現(xiàn)一個(gè)類似go的關(guān)鍵字,那該多好啊!
思路
Java本身也是支持閉包的,通過(guò)閉包重建一個(gè)java.lang.Runnable
的匿名實(shí)現(xiàn)類,然后創(chuàng)建線程去執(zhí)行對(duì)應(yīng)的方法,應(yīng)該是可以實(shí)現(xiàn)簡(jiǎn)單異步功能。
既然Java都能支持,那Groovy肯定也有解決方案了,至少可以直接用Java的方案。
幾種語(yǔ)言的閉包使用可以參考
實(shí)踐
思路比較簡(jiǎn)單,下面分享一下實(shí)踐過(guò)程。
Java
不同于其他語(yǔ)言,Java閉包方法根據(jù)不同的參數(shù)、返回值有不同的實(shí)現(xiàn)類。這個(gè)地方有點(diǎn)煩,不夠靈活。我試了java.util.function
下面的多個(gè)實(shí)現(xiàn)類,最終選擇了java.util.function.Supplier
,原因是這個(gè)實(shí)現(xiàn)類沒(méi)有參數(shù),但是需要一個(gè)返回值。
There is no requirement that a new or distinct result be returned each time the supplier is invoked.
代碼和使用方式如下:
package com.funtest.javatest;
import com.funtester.frame.SourceCode;
import java.util.function.Supplier;
public class Sync extends SourceCode {
public static void main(String[] args) {
sync(() -> {
sleep(0.1);
output("tester");
return DEFAULT_CHARSET;
});
output("FunTester");
}
public static void sync(Supplier f) {
new Thread(() -> {
f.get();
}).start();
}
}
控制臺(tái)輸出:
INFO-> main 當(dāng)前用戶:oker,工作目錄:/Users/oker/IdeaProjects/funtester/,系統(tǒng)編碼格式:UTF-8,系統(tǒng)Mac OS X版本:10.16
INFO-> main FunTester
INFO-> Thread-1 tester
Process finished with exit code 0
這里先不展示Groovy如何使用了。后面有更精彩的。
Groovy
Groovy語(yǔ)法相當(dāng)簡(jiǎn)單,用一個(gè)groovy.lang.Closure
解決所有問(wèn)題。
代碼和使用方式如下:
import com.funtester.frame.SourceCode
class Sync extends SourceCode {
public static void main(String[] args) {
sync {
sleep(0.2)
output(320)
}
output("FunTester")
}
static void sync(Closure f) {
new Thread(f()).start()
}
}
控制臺(tái)輸出:
INFO-> main 當(dāng)前用戶:oker,工作目錄:/Users/oker/IdeaProjects/funtester/,系統(tǒng)編碼格式:UTF-8,系統(tǒng)Mac OS X版本:10.16
INFO-> main FunTester
INFO-> Thread-1 tester
Process finished with exit code 0
可以看出Groovy語(yǔ)法是非常簡(jiǎn)單的,已經(jīng)非常接近Golang語(yǔ)言go關(guān)鍵字的體驗(yàn)了,僅僅從語(yǔ)法上,性能上的問(wèn)題以后會(huì)再討論。
線程池升級(jí)
因?yàn)镚olang語(yǔ)言有自己的goroutine管理器,加上Golang特性,所以不是用很擔(dān)心創(chuàng)建過(guò)多的協(xié)程消耗更多資源。但是Java還是要考慮一下的,為了解決測(cè)試過(guò)程中創(chuàng)建過(guò)多線程導(dǎo)致異常出現(xiàn),我用線程池解決這個(gè)問(wèn)題。通過(guò)將閉包中的方法包裝成java.lang.Runnable
對(duì)象,丟給線程池去執(zhí)行。
封裝方法如下:
/**
* 異步執(zhí)行某個(gè)代碼塊
* Java調(diào)用需要return,Groovy也不需要,語(yǔ)法兼容
*
* @param f
*/
public static void fun(Supplier f) {
Runnable runnable = new Runnable() {
@Override
public void run() {
f.get();
}
};
ThreadPoolUtil.executeSync(runnable);
}
這里我選用了Java的語(yǔ)法,為什么不用Groovy的方法封裝呢?因?yàn)镚roovy完全兼容了Java的語(yǔ)法而不失去Groovy自己的特性。
下面演示一下Java如何使用:
public class FunT extends FunLibrary {
public static void main(String[] args) {
fun(()->{
sleep(0.1);
output("FunTester");
return null;
});
output("fds");
ThreadPoolUtil.shutFun()
}
}
優(yōu)先于Java語(yǔ)法,需要多寫一些code,這個(gè)我目前解決方案是通過(guò)Intellij
自帶的Live Templates
輸入代碼模板解決。如圖:
下面演示一下Groovy如何使用:
public static void main(String[] args) {
fun {
sleep(0.2)
output(320)
}
output("FunTester")
ThreadPoolUtil.shutFun()
}
同樣我們可以使用Intellij
自帶的Live Templates
輸入代碼模板,不再展示了。
簡(jiǎn)直如絲般順滑。
控制臺(tái)輸出:
INFO-> main 當(dāng)前用戶:oker,工作目錄:/Users/oker/IdeaProjects/funtester/,系統(tǒng)編碼格式:UTF-8,系統(tǒng)Mac OS X版本:10.16
INFO-> main FunTester
INFO-> FT-1 320
Process finished with exit code 0
這里我自定義了線程的名字,方法如下:
/**
* 自定義{@link ThreadFactory}對(duì)象
* @return
*/
static ThreadFactory getFactory() {
if (FunFactory == null) {
synchronized (ThreadPoolUtil.class) {
if (FunFactory == null) {
FunFactory = new ThreadFactory() {
@Override
Thread newThread(Runnable runnable) {
Thread thread = new Thread(runnable);
def increment = threadNum.getAndIncrement()
def name = increment < 10 ? "00" + increment : increment < 100 ? "0" + increment : Constant.EMPTY + increment
thread.setName("FT-" + name);
return thread;
}
}
}
}
}
return FunFactory
}
多線程同步
如果遇到有多線程同步需求,那么依舊使用java.util.concurrent.Phaser
來(lái)滿足需求。封裝方法如下:
/**
* 異步執(zhí)行代碼塊,使用{@link Phaser}進(jìn)行多線程同步
*
* @param f
* @param phaser
*/
public static void fun(Supplier f, Phaser phaser) {
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
phaser.register();
f.get();
} catch (Exception e) {
logger.warn("執(zhí)行異步方法時(shí)發(fā)生錯(cuò)誤!", e);
} finally {
phaser.arriveAndDeregister();
}
}
};
ThreadPoolUtil.executeSync(runnable);
}
Have Fun ~ Tester !
- FunTester測(cè)試框架架構(gòu)圖初探
- 頗具年代感的《JMeter中文操作手冊(cè)》
- 140道面試題目(UI、Linux、MySQL、API、安全)
- 圖解HTTP腦圖
- 分享一份Fiddler學(xué)習(xí)包
- 測(cè)試之JVM命令腦圖
- 好書(shū)推薦《Java性能權(quán)威指南》
- JSON基礎(chǔ)
- HTTP異步連接池和多線程實(shí)踐
- 綁定手機(jī)號(hào)性能測(cè)試
- 性能測(cè)試中集合點(diǎn)和多階段同步問(wèn)題初探
- 如何成為全棧自動(dòng)化工程師
- LT瀏覽器——響應(yīng)式網(wǎng)站測(cè)試?yán)?/a>
- 簡(jiǎn)化測(cè)試用例