Java多執行緒系列--“JUC執行緒池”05之 執行緒池原理(四)
阿新 • • 發佈:2018-12-10
概要
本章介紹執行緒池的拒絕策略。內容包括:
- 拒絕策略介紹
- 拒絕策略對比和示例
拒絕策略介紹
執行緒池的拒絕策略,是指當任務新增到執行緒池中被拒絕,而採取的處理措施。 當任務新增到執行緒池中之所以被拒絕,可能是由於:第一,執行緒池異常關閉。第二,任務數量超過執行緒池的最大限制。
執行緒池共包括4種拒絕策略,它們分別是:AbortPolicy
, CallerRunsPolicy
, DiscardOldestPolicy
和DiscardPolicy
。
AbortPolicy -- 當任務新增到執行緒池中被拒絕時,它將丟擲 RejectedExecutionException 異常。 CallerRunsPolicy -- 當任務新增到執行緒池中被拒絕時,會線上程池當前正在執行的Thread執行緒池中處理被拒絕的任務。 DiscardOldestPolicy -- 當任務新增到執行緒池中被拒絕時,執行緒池會放棄等待佇列中最舊的未處理任務,然後將被拒絕的任務新增到等待佇列中。 DiscardPolicy -- 當任務新增到執行緒池中被拒絕時,執行緒池將丟棄被拒絕的任務。
執行緒池預設的處理策略是AbortPolicy
!
拒絕策略對比和示例
下面通過示例,分別演示執行緒池的4種拒絕策略。
- DiscardPolicy 示例;
- DiscardOldestPolicy 示例;
- AbortPolicy 示例;
- CallerRunsPolicy 示例;
1、DiscardPolicy 示例
import java.lang.reflect.Field;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java. util.concurrent.TimeUnit;
import java.util.concurrent.ThreadPoolExecutor.DiscardPolicy;
public class DiscardPolicyDemo {
private static final int THREADS_SIZE = 1;
private static final int CAPACITY = 1;
public static void main(String[] args) throws Exception {
// 建立執行緒池。執行緒池的"最大池大小"和"核心池大小"都為1(THREADS_SIZE),"執行緒池"的阻塞佇列容量為1(CAPACITY)。
ThreadPoolExecutor pool = new ThreadPoolExecutor(THREADS_SIZE, THREADS_SIZE, 0, TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(CAPACITY));
// 設定執行緒池的拒絕策略為"丟棄"
pool.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
// 新建10個任務,並將它們新增到執行緒池中。
for (int i = 0; i < 10; i++) {
Runnable myrun = new MyRunnable("task-"+i);
pool.execute(myrun);
}
// 關閉執行緒池
pool.shutdown();
}
}
class MyRunnable implements Runnable {
private String name;
public MyRunnable(String name) {
this.name = name;
}
@Override
public void run() {
try {
System.out.println(this.name + " is running.");
Thread.sleep(100);
} catch (Exception e) {
e.printStackTrace();
}
}
}
執行結果:
task-0 is running.
task-1 is running.
結果說明:
- 執行緒池pool的"最大池大小"和"核心池大小"都為1(THREADS_SIZE),這意味著"執行緒池能同時執行的任務數量最大隻能是1"。
- 執行緒池pool的阻塞佇列是ArrayBlockingQueue,ArrayBlockingQueue是一個有界的阻塞佇列,ArrayBlockingQueue的容量為1。這也意味著執行緒池的阻塞佇列只能有一個執行緒池阻塞等待。
根據""中分析的execute()程式碼可知:執行緒池中共運行了2個任務。第1個任務直接放到Worker中,通過執行緒去執行;第2個任務放到阻塞佇列中等待。其他的任務都被丟棄了!
2、DiscardOldestPolicy 示例
import java.lang.reflect.Field;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.ThreadPoolExecutor.DiscardOldestPolicy;
public class DiscardOldestPolicyDemo {
private static final int THREADS_SIZE = 1;
private static final int CAPACITY = 1;
public static void main(String[] args) throws Exception {
// 建立執行緒池。執行緒池的"最大池大小"和"核心池大小"都為1(THREADS_SIZE),"執行緒池"的阻塞佇列容量為1(CAPACITY)。
ThreadPoolExecutor pool = new ThreadPoolExecutor(THREADS_SIZE, THREADS_SIZE, 0, TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(CAPACITY));
// 設定執行緒池的拒絕策略為"DiscardOldestPolicy"
pool.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());
// 新建10個任務,並將它們新增到執行緒池中。
for (int i = 0; i < 10; i++) {
Runnable myrun = new MyRunnable("task-"+i);
pool.execute(myrun);
}
// 關閉執行緒池
pool.shutdown();
}
}
class MyRunnable implements Runnable {
private String name;
public MyRunnable(String name) {
this.name = name;
}
@Override
public void run() {
try {
System.out.println(this.name + " is running.");
Thread.sleep(200);
} catch (Exception e) {
e.printStackTrace();
}
}
}
執行結果:
task-0 is running.
task-9 is running.
結果說明:將"執行緒池的拒絕策略"由DiscardPolicy修改為DiscardOldestPolicy之後,當有任務新增到執行緒池被拒絕時,執行緒池會丟棄阻塞佇列中末尾的任務,然後將被拒絕的任務新增到末尾。
3、AbortPolicy 示例
import java.lang.reflect.Field;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.ThreadPoolExecutor.AbortPolicy;
import java.util.concurrent.RejectedExecutionException;
public class AbortPolicyDemo {
private static final int THREADS_SIZE = 1;
private static final int CAPACITY = 1;
public static void main(String[] args) throws Exception {
// 建立執行緒池。執行緒池的"最大池大小"和"核心池大小"都為1(THREADS_SIZE),"執行緒池"的阻塞佇列容量為1(CAPACITY)。
ThreadPoolExecutor pool = new ThreadPoolExecutor(THREADS_SIZE, THREADS_SIZE, 0, TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(CAPACITY));
// 設定執行緒池的拒絕策略為"丟擲異常"
pool.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
try {
// 新建10個任務,並將它們新增到執行緒池中。
for (int i = 0; i < 10; i++) {
Runnable myrun = new MyRunnable("task-"+i);
pool.execute(myrun);
}
} catch (RejectedExecutionException e) {
e.printStackTrace();
// 關閉執行緒池
pool.shutdown();
}
}
}
class MyRunnable implements Runnable {
private String name;
public MyRunnable(String name) {
this.name = name;
}
@Override
public void run() {
try {
System.out.println(this.name + " is running.");
Thread.sleep(200);
} catch (Exception e) {
e.printStackTrace();
}
}
}
(某一次)執行結果:
java.util.concurrent.RejectedExecutionException
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:1774)
at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:768)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:656)
at AbortPolicyDemo.main(AbortPolicyDemo.java:27)
task-0 is running.
task-1 is running.
結果說明:將"執行緒池的拒絕策略"由DiscardPolicy修改為AbortPolicy之後,當有任務新增到執行緒池被拒絕時,會丟擲RejectedExecutionException。
4、CallerRunsPolicy 示例
import java.lang.reflect.Field;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy;
public class CallerRunsPolicyDemo {
private static final int THREADS_SIZE = 1;
private static final int CAPACITY = 1;
public static void main(String[] args) throws Exception {
// 建立執行緒池。執行緒池的"最大池大小"和"核心池大小"都為1(THREADS_SIZE),"執行緒池"的阻塞佇列容量為1(CAPACITY)。
ThreadPoolExecutor pool = new ThreadPoolExecutor(THREADS_SIZE, THREADS_SIZE, 0, TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(CAPACITY));
// 設定執行緒池的拒絕策略為"CallerRunsPolicy"
pool.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 新建10個任務,並將它們新增到執行緒池中。
for (int i = 0; i < 10; i++) {
Runnable myrun = new MyRunnable("task-"+i);
pool.execute(myrun);
}
// 關閉執行緒池
pool.shutdown();
}
}
class MyRunnable implements Runnable {
private String name;
public MyRunnable(String name) {
this.name = name;
}
@Override
public void run() {
try {
System.out.println(this.name + " is running.");
Thread.sleep(100);
} catch (Exception e) {
e.printStackTrace();
}
}
}
(某一次)執行結果:
task-2 is running.
task-3 is running.
task-4 is running.
task-5 is running.
task-6 is running.
task-7 is running.
task-8 is running.
task-9 is running.
task-0 is running.
task-1 is running.
結果說明:將"執行緒池的拒絕策略"由DiscardPolicy修改為CallerRunsPolicy之後,當有任務新增到執行緒池被拒絕時,執行緒池會將被拒絕的任務新增到"執行緒池正在執行的執行緒"中取執行。