當(dāng)前位置:首頁 > IT技術(shù) > 編程語言 > 正文

利用守護線程隱式關(guān)閉線程池
2021-10-27 14:30:21

在上期[??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 !


本文摘自 :https://blog.51cto.com/F

開通會員,享受整站包年服務(wù)立即開通 >