日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

转: java多线程-ThreadPoolExecutor的拒绝策略RejectedExecutionHandler

發(fā)布時間:2023/12/3 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 转: java多线程-ThreadPoolExecutor的拒绝策略RejectedExecutionHandler 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

轉(zhuǎn)自:? https://blog.csdn.net/qq_25806863/article/details/71172823

?

概述

原文地址 http://blog.csdn.net/qq_25806863/article/details/71172823

在分析ThreadPoolExecutor的構(gòu)造參數(shù)時,有一個RejectedExecutionHandler參數(shù)。

RejectedExecutionHandler是一個接口:

public interface RejectedExecutionHandler {
??? void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
}

??? 1
??? 2
??? 3

里面只有一個方法。當(dāng)要創(chuàng)建的線程數(shù)量大于線程池的最大線程數(shù)的時候,新的任務(wù)就會被拒絕,就會調(diào)用這個接口里的這個方法。

可以自己實現(xiàn)這個接口,實現(xiàn)對這些超出數(shù)量的任務(wù)的處理。

ThreadPoolExecutor自己已經(jīng)提供了四個拒絕策略,分別是CallerRunsPolicy,AbortPolicy,DiscardPolicy,DiscardOldestPolicy

這四個拒絕策略其實一看實現(xiàn)方法就知道很簡單。
AbortPolicy

ThreadPoolExecutor中默認(rèn)的拒絕策略就是AbortPolicy。直接拋出異常。

private static final RejectedExecutionHandler defaultHandler =
??? new AbortPolicy();

??? 1
??? 2

下面是他的實現(xiàn):

public static class AbortPolicy implements RejectedExecutionHandler {
??? public AbortPolicy() { }
??? public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
??????? throw new RejectedExecutionException("Task " + r.toString() +
???????????????????????????????????????????? " rejected from " +
???????????????????????????????????????????? e.toString());
??? }
}

??? 1
??? 2
??? 3
??? 4
??? 5
??? 6
??? 7
??? 8

很簡單粗暴,直接拋出個RejectedExecutionException異常,也不執(zhí)行這個任務(wù)了。
測試

先自定義一個Runnable,給每個線程起個名字,下面都用這個Runnable

static class MyThread implements Runnable {
??????? String name;
??????? public MyThread(String name) {
??????????? this.name = name;
??????? }
??????? @Override
??????? public void run() {
??????????? try {
??????????????? Thread.sleep(2000);
??????????? } catch (InterruptedException e) {
??????????????? e.printStackTrace();
??????????? }
??????????? System.out.println("線程:"+Thread.currentThread().getName() +" 執(zhí)行:"+name +"? run");
??????? }
??? }

??? 1
??? 2
??? 3
??? 4
??? 5
??? 6
??? 7
??? 8
??? 9
??? 10
??? 11
??? 12
??? 13
??? 14
??? 15

然后構(gòu)造一個核心線程是1,最大線程數(shù)是2的線程池。拒絕策略是AbortPolicy

ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 2, 0,
??????? TimeUnit.MICROSECONDS,
??????? new LinkedBlockingDeque<Runnable>(2),
??????? new ThreadPoolExecutor.AbortPolicy());

??? 1
??? 2
??? 3
??? 4

for (int i = 0; i < 6; i++) {
??? System.out.println("添加第"+i+"個任務(wù)");
??? executor.execute(new MyThread("線程"+i));
??? Iterator iterator = executor.getQueue().iterator();
??? while (iterator.hasNext()){
??????? MyThread thread = (MyThread) iterator.next();
??????? System.out.println("列表:"+thread.name);
??? }
}

??? 1
??? 2
??? 3
??? 4
??? 5
??? 6
??? 7
??? 8
??? 9

輸出是:

這里寫圖片描述

分析一下過程。

??? 添加第一個任務(wù)時,直接執(zhí)行,任務(wù)列表為空。
??? 添加第二個任務(wù)時,因為采用的LinkedBlockingDeque,,并且核心線程正在執(zhí)行任務(wù),所以會將第二個任務(wù)放在隊列中,隊列中有 線程2.
??? 添加第三個任務(wù)時,也一樣會放在隊列中,隊列中有 線程2,線程3.
??? 添加第四個任務(wù)時,因為核心任務(wù)還在運行,而且任務(wù)隊列已經(jīng)滿了,所以胡直接創(chuàng)建新線程執(zhí)行第四個任務(wù),。這時線程池中一共就有兩個線程在運行了,達(dá)到了最大線程數(shù)。任務(wù)隊列中還是有線程2, 線程3.
??? 添加第五個任務(wù)時,再也沒有地方能存放和執(zhí)行這個任務(wù)了,就會被線程池拒絕添加,執(zhí)行拒絕策略的rejectedExecution方法,這里就是執(zhí)行AbortPolicy的rejectedExecution方法直接拋出異常。
??? 最終,只有四個線程能完成運行。后面的都被拒絕了。

CallerRunsPolicy

CallerRunsPolicy在任務(wù)被拒絕添加后,會調(diào)用當(dāng)前線程池的所在的線程去執(zhí)行被拒絕的任務(wù)。

下面說他的實現(xiàn):

public static class CallerRunsPolicy implements RejectedExecutionHandler {
??? public CallerRunsPolicy() { }
??? public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
??????? if (!e.isShutdown()) {
??????????? r.run();
??????? }
??? }
}

??? 1
??? 2
??? 3
??? 4
??? 5
??? 6
??? 7
??? 8

也很簡單,直接run。
測試

ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 2, 30,
??????? TimeUnit.SECONDS,
??????? new LinkedBlockingDeque<Runnable>(2),
??????? new ThreadPoolExecutor.AbortPolicy());

??? 1
??? 2
??? 3
??? 4

按上面的運行,輸出

這里寫圖片描述

注意在添加第五個任務(wù),任務(wù)5 的時候,同樣被線程池拒絕了,因此執(zhí)行了CallerRunsPolicy的rejectedExecution方法,這個方法直接執(zhí)行任務(wù)的run方法。因此可以看到任務(wù)5是在main線程中執(zhí)行的。

從中也可以看出,因為第五個任務(wù)在主線程中運行,所以主線程就被阻塞了,以至于當(dāng)?shù)谖鍌€任務(wù)執(zhí)行完,添加第六個任務(wù)時,前面兩個任務(wù)已經(jīng)執(zhí)行完了,有了空閑線程,因此線程6又可以添加到線程池中執(zhí)行了。

這個策略的缺點就是可能會阻塞主線程。
DiscardPolicy

這個策略的處理就更簡單了,看一下實現(xiàn)就明白了:

public static class DiscardPolicy implements RejectedExecutionHandler {
??? public DiscardPolicy() { }
??? public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
??? }
}

??? 1
??? 2
??? 3
??? 4
??? 5

這個東西什么都沒干。

因此采用這個拒絕策略,會讓被線程池拒絕的任務(wù)直接拋棄,不會拋異常也不會執(zhí)行。
測試

ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 2, 30,
??????? TimeUnit.SECONDS,
??????? new LinkedBlockingDeque<Runnable>(2),
??????? new ThreadPoolExecutor.DiscardPolicy());

??? 1
??? 2
??? 3
??? 4

輸出:

這里寫圖片描述

可以看到 后面添加的任務(wù)5和6根本不會執(zhí)行,什么反應(yīng)都沒有,直接丟棄。
DiscardOldestPolicy

DiscardOldestPolicy策略的作用是,當(dāng)任務(wù)唄拒絕添加時,會拋棄任務(wù)隊列中最舊的任務(wù)也就是最先加入隊列的,再把這個新任務(wù)添加進(jìn)去。

public static class DiscardOldestPolicy implements RejectedExecutionHandler {
??? public DiscardOldestPolicy() { }
??? public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
??????? if (!e.isShutdown()) {
??????????? e.getQueue().poll();
??????????? e.execute(r);
??????? }
??? }
}

??? 1
??? 2
??? 3
??? 4
??? 5
??? 6
??? 7
??? 8
??? 9

在rejectedExecution先從任務(wù)隊列總彈出最先加入的任務(wù),空出一個位置,然后再次執(zhí)行execute方法把任務(wù)加入隊列。
測試

ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 2, 30,
??????? TimeUnit.SECONDS,
??????? new LinkedBlockingDeque<Runnable>(2),
??????? new ThreadPoolExecutor.DiscardOldestPolicy());

??? 1
??? 2
??? 3
??? 4

輸出是:

這里寫圖片描述

可以看到,

??? 在添加第五個任務(wù)時,會被線程池拒絕。這時任務(wù)隊列中有 任務(wù)2,任務(wù)3
??? 這時,拒絕策略會讓任務(wù)隊列中最先加入的任務(wù)彈出,也就是任務(wù)2.
??? 然后把被拒絕的任務(wù)5添加人任務(wù)隊列,這時任務(wù)隊列中就成了 任務(wù)3,任務(wù)5.
??? 添加第六個任務(wù)時會因為同樣的過程,將隊列中的任務(wù)3拋棄,把任務(wù)6加進(jìn)去,任務(wù)隊列中就成了 任務(wù)5,任務(wù)6
??? 因此,最終能被執(zhí)行的任務(wù)只有1,4,5,6. 任務(wù)2和任務(wù)3倍拋棄了,不會執(zhí)行。

自定義拒絕策略

通過看前面的系統(tǒng)提供的四種拒絕策略可以看出,拒絕策略的實現(xiàn)都非常簡單。自己寫亦一樣

比如現(xiàn)在想讓被拒絕的任務(wù)在一個新的線程中執(zhí)行,可以這樣寫:

static class MyRejectedExecutionHandler implements RejectedExecutionHandler {
??? @Override
??? public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
??????? new Thread(r,"新線程"+new Random().nextInt(10)).start();
??? }
}

??? 1
??? 2
??? 3
??? 4
??? 5
??? 6

然后正常使用:

ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 2, 30,
??????? TimeUnit.SECONDS,
??????? new LinkedBlockingDeque<Runnable>(2),
??????? new MyRejectedExecutionHandler());

??? 1
??? 2
??? 3
??? 4

輸出:

這里寫圖片描述

發(fā)現(xiàn)被拒絕的任務(wù)5和任務(wù)6都在新線程中執(zhí)行了。
?

總結(jié)

以上是生活随笔為你收集整理的转: java多线程-ThreadPoolExecutor的拒绝策略RejectedExecutionHandler的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。