在上期[??Java自定義異步功能實踐??文章中,我設(shè)計了一個關(guān)鍵字,傳入一個閉包,然后異步執(zhí)行閉包中的代碼塊。但是在實際工作中情況又更復(fù)雜了一些。因為在創(chuàng)建執(zhí)行異步方法的線程池時候,遇到了一些問題。
- 如何創(chuàng)建線程池core數(shù)值大于1,就必須手動關(guān)閉線程池
- 如果創(chuàng)建線程池core=0,那么必須設(shè)置一個不為零的workQueue
- 如果workQueue設(shè)置太小,無法容納更多任務(wù)
- 如果workQueue設(shè)置太大,無法新建更多線程(實際中只有1個線程被創(chuàng)建)
經(jīng)過一些人生的思考,我覺定使用守護進程來解決這個問題。參考[??創(chuàng)建Java守護線程??。
思路執(zhí)行異步方法的線程池,我使用定長線程池,設(shè)置線程數(shù)16,因為這個場景主要是在批量執(zhí)行腳本使用,所以效率優(yōu)先。設(shè)置workQueue為1百萬(或者10萬),目前使用中沒有差別。 如何在測試結(jié)束之后,利用守護進程的特性,等待main線程執(zhí)行結(jié)束,然后回收資源。 為了避免浪費,只在使用異步功能時再啟用這個守護進程。
分步實現(xiàn)創(chuàng)建線程池
方法如下:
Java
private static volatile ExecutorService funPool;
/**
* 獲取異步任務(wù)連接池
* @return
*/
static ExecutorService getFunPool() {
if (funPool == null) {
synchronized (ThreadPoolUtil.class) {
if (funPool == null) {
funPool = createFixedPool(Constant.POOL_SIZE);
daemon()
}
}
}
return funPool
}
創(chuàng)建守護線程
Java
/**
* 執(zhí)行daemon線程,保障main方法結(jié)束后關(guān)閉線程池
* @return
*/
static boolean daemon() {
def thread = new Thread(new Runnable() {
@Override
void run() {
while (checkMain()) {
SourceCode.sleep(1.0)
}
ThreadPoolUtil.shutFun()
}
})
thread.setDaemon(true)
thread.setName("FT-D")
thread.start()
logger.info("守護線程:{}開啟!", thread.getName())
}
檢查main線程是否存活
Java
/**
* 檢查main線程是否存活
* @return
*/
static boolean checkMain() {
def count = Thread.activeCount()
def group = Thread.currentThread().getThreadGroup()
def threads = new Thread[count]
group.enumerate(threads)
for (i in 0..
測試腳本
簡單使用了Groovy語法糖中??times?
?語法,含義就是從0~20遍歷閉包內(nèi)容,it表示遍歷索引,從0開始到19。
Java
public static void main(String[] args) {
20.times {
def a = it as String
fun{
sleep(1.0)
output(StringUtil.right("index:" + a, 10) + Time.getNow())
}
}
}
下面寫個Java版本的比較容易理解:
Java
public static void main(String[] args) {
for (int i = 0; i < 20; i++) {
Integer a = i;
fun(() -> {
sleep(1.0);
output(StringUtil.right("index:" + a, 10) + Time.getNow());
return null;
});
}
}
控制臺輸出
ll
INFO-> main 當(dāng)前用戶:oker,工作目錄:/Users/oker/IdeaProjects/funtester/,系統(tǒng)編碼格式:UTF-8,系統(tǒng)Mac OS X版本:10.16
INFO-> main 守護線程:FT-D開啟!
INFO-> FT-13 index:12 20211011182658
INFO-> FT-3 index:2 20211011182658
INFO-> FT-16 index:15 20211011182658
INFO-> FT-14 index:13 20211011182658
INFO-> FT-5 index:4 20211011182658
INFO-> FT-4 index:3 20211011182658
INFO-> FT-12 index:11 20211011182658
WARN-> FT-D 異步線程池關(guān)閉!
INFO-> FT-10 index:9 20211011182658
INFO-> FT-7 index:6 20211011182658
INFO-> FT-2 index:1 20211011182658
INFO-> FT-11 index:10 20211011182658
INFO-> FT-8 index:7 20211011182658
INFO-> FT-15 index:14 20211011182658
INFO-> FT-1 index:0 20211011182658
INFO-> FT-9 index:8 20211011182658
INFO-> FT-6 index:5 20211011182658
INFO-> FT-16 index:16 20211011182659
INFO-> FT-7 index:19 20211011182659
INFO-> FT-5 index:17 20211011182659
INFO-> FT-12 index:18 20211011182659
Process finished with exit code 0
多線程同步依然使用??java.util.concurrent.Phaser?
?類,不過加上這個參數(shù)后有點破壞原來優(yōu)雅的語法。
Groovy版本:
Java
public static void main(String[] args) {
def phaser = new Phaser(1)
20.times {
def a = it as String
fun {
sleep(1.0)
output(StringUtil.right("index:" + a, 10) + Time.getNow())
} , phaser
}
phaser.arriveAndAwaitAdvance()
}
這么寫還是非常舒服的,不過編譯器會報錯,請忽略,編譯器也不一定都是正確的。 Java版本:
Java
public static void main(String[] args) {
Phaser phaser = new Phaser(1);
for (int i = 0; i < 20; i++) {
Integer a = i;
fun(() -> {
sleep(1.0);
output(StringUtil.right("index:" + a, 10) + Time.getNow());
return null;
},phaser);
}
phaser.arriveAndAwaitAdvance();
}
控制臺輸出:
ll
INFO-> main 當(dāng)前用戶:oker,工作目錄:/Users/oker/IdeaProjects/funtester/,系統(tǒng)編碼格式:UTF-8,系統(tǒng)Mac OS X版本:10.16
INFO-> main 守護線程:FT-D開啟!
INFO-> FT-11 index:10 20211011185814
INFO-> FT-1 index:0 20211011185814
INFO-> FT-5 index:4 20211011185814
INFO-> FT-3 index:2 20211011185814
INFO-> FT-16 index:15 20211011185814
INFO-> FT-10 index:9 20211011185814
INFO-> FT-7 index:6 20211011185814
INFO-> FT-14 index:13 20211011185814
INFO-> FT-9 index:8 20211011185814
INFO-> FT-12 index:11 20211011185814
INFO-> FT-15 index:14 20211011185814
INFO-> FT-8 index:7 20211011185814
INFO-> FT-6 index:5 20211011185814
INFO-> FT-13 index:12 20211011185814
INFO-> FT-2 index:1 20211011185814
INFO-> FT-4 index:3 20211011185814
INFO-> FT-3 index:16 20211011185815
INFO-> FT-15 index:19 20211011185815
INFO-> FT-7 index:18 20211011185815
INFO-> FT-16 index:17 20211011185815
WARN-> FT-D 異步線程池關(guān)閉!
Process finished with exit code 0
可以看到??WARN-> FT-D 異步線程池關(guān)閉!?
?是最后打印的,符合預(yù)期。
Have Fun ~ Tester !
- [??FunTester測試框架架構(gòu)圖初探??
- [??頗具年代感的《JMeter中文操作手冊》??
- [??140道面試題目(UI、Linux、MySQL、API、安全)??
- [??圖解HTTP腦圖??
- [??分享一份Fiddler學(xué)習(xí)包??
- [??測試之JVM命令腦圖??
- [??好書推薦《Java性能權(quán)威指南》??
- [??JSON基礎(chǔ)??
- [??Math.abs()求絕對值返回負值BUG分享??
- [??moco框架接口命中率統(tǒng)計實踐??
- [??性能測試中集合點和多階段同步問題初探??
- [??利用 python+plotly 制作雙波源干涉三維圖像??
- [??代碼審查如何保證軟件質(zhì)量??
- [??自動化如何選擇用例??
本文摘自 :https://blog.51cto.com/F