日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

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

轉自:? https://blog.csdn.net/qq_25806863/article/details/71172823

?

概述

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

在分析ThreadPoolExecutor的構造參數時,有一個RejectedExecutionHandler參數。

RejectedExecutionHandler是一個接口:

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

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

里面只有一個方法。當要創建的線程數量大于線程池的最大線程數的時候,新的任務就會被拒絕,就會調用這個接口里的這個方法。

可以自己實現這個接口,實現對這些超出數量的任務的處理。

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

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

ThreadPoolExecutor中默認的拒絕策略就是AbortPolicy。直接拋出異常。

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

??? 1
??? 2

下面是他的實現:

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異常,也不執行這個任務了。
測試

先自定義一個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() +" 執行:"+name +"? run");
??????? }
??? }

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

然后構造一個核心線程是1,最大線程數是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+"個任務");
??? 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

輸出是:

這里寫圖片描述

分析一下過程。

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

CallerRunsPolicy

CallerRunsPolicy在任務被拒絕添加后,會調用當前線程池的所在的線程去執行被拒絕的任務。

下面說他的實現:

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

按上面的運行,輸出

這里寫圖片描述

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

從中也可以看出,因為第五個任務在主線程中運行,所以主線程就被阻塞了,以至于當第五個任務執行完,添加第六個任務時,前面兩個任務已經執行完了,有了空閑線程,因此線程6又可以添加到線程池中執行了。

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

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

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

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

這個東西什么都沒干。

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

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

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

輸出:

這里寫圖片描述

可以看到 后面添加的任務5和6根本不會執行,什么反應都沒有,直接丟棄。
DiscardOldestPolicy

DiscardOldestPolicy策略的作用是,當任務唄拒絕添加時,會拋棄任務隊列中最舊的任務也就是最先加入隊列的,再把這個新任務添加進去。

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先從任務隊列總彈出最先加入的任務,空出一個位置,然后再次執行execute方法把任務加入隊列。
測試

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

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

輸出是:

這里寫圖片描述

可以看到,

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

自定義拒絕策略

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

比如現在想讓被拒絕的任務在一個新的線程中執行,可以這樣寫:

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

輸出:

這里寫圖片描述

發現被拒絕的任務5和任務6都在新線程中執行了。
?

總結

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

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。