一、线程池的阻塞策略主要有以下几种:
AbortPolicy:这是默认阻塞策略,当线程队列和空闲线程都无法处理新任务时,新任务提交会直接抛出异常RejectedExecutionException,该异常可以由调用者捕获。
CallerRunsPolicy:这个策略会尝试调节机制,既不抛弃任务也不抛出异常,而是将某些任务回退到调用者,由调用任务的线程来执行。
DiscardPolicy:这个策略会抛弃新提交的任务,不进行处理。
DiscardOldestPolicy:这个策略会抛弃队列中最后一个任务,然后执行新进来的任务。
自定义策略:除了上面提到的四种常见的拒绝策略(AbortPolicy、CallerRunsPolicy、DiscardPolicy和DiscardOldestPolicy),您也可以通过自定义实现RejectedExecutionHandler
接口来定义自己的拒绝策略。
二、策略的举例说明
这些是线程池中常见的拒绝策略,它们用于处理在线程池已满时无法接收新任务的情况。下面我会给出这4种拒绝策略的例子:
- AbortPolicy(默认的拒绝策略):直接抛出RejectedExecutionException异常。
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class AbortPolicyExample {
public static void main(String[] args) {
ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(1), new ThreadPoolExecutor.AbortPolicy());
// 提交5个任务,线程池无法处理超过1个任务,将抛出RejectedExecutionException异常
for (int i = 1; i <= 5; i++) {
final int taskId = i;
executor.submit(() -> {
System.out.println("Task " + taskId + " executed by " + Thread.currentThread().getName());
});
}
executor.shutdown();
}
}
在此示例中,线程池最大线程数设置为1,工作队列长度也为1。当同时提交5个任务时,第一个任务能够被执行,但对于其余的任务,线程池将抛出RejectedExecutionException
异常。
- CallerRunsPolicy:让提交拒绝的任务在提交线程上执行。
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class CallerRunsPolicyExample {
public static void main(String[] args) {
ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(1), new ThreadPoolExecutor.CallerRunsPolicy());
// 提交5个任务,线程池无法处理超过1个任务,调用线程将执行剩下的4个任务
for (int i = 1; i <= 5; i++) {
final int taskId = i;
executor.submit(() -> {
System.out.println("Task " + taskId + " executed by " + Thread.currentThread().getName());
});
}
executor.shutdown();
}
}
在此示例中,线程池最大线程数设置为1,工作队列长度也为1。当同时提交5个任务时,第一个任务能够被执行,但对于其余的任务,线程池将不会抛出异常,而是将任务交由提交线程来执行。
- DiscardPolicy:直接丢弃无法处理的任务,不提供任何反馈。
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class DiscardPolicyExample {
public static void main(String[] args) {
ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(1), new ThreadPoolExecutor.DiscardPolicy());
// 提交5个任务,线程池无法处理超过1个任务,多余的任务将被直接丢弃
for (int i = 1; i <= 5; i++) {
final int taskId = i;
executor.submit(() -> {
System.out.println("Task " + taskId + " executed by " + Thread.currentThread().getName());
});
}
executor.shutdown();
}
}
在此示例中,线程池最大线程数设置为1,工作队列长度也为1。当同时提交5个任务时,第一个任务能够被执行,但对于其余的任务,线程池将直接丢弃它们。
- DiscardOldestPolicy:丢弃最旧的任务,并尝试再次提交新任务。
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class DiscardOldestPolicyExample {
public static void main(String[] args) {
ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(1), new ThreadPoolExecutor.DiscardOldestPolicy());
// 提交5个任务,线程池无法处理超过1个任务,多余的任务将丢弃最旧的任务
for (int i = 1; i <= 5; i++) {
final int taskId = i;
executor.submit(() -> {
System.out.println("Task " + taskId + " executed by " + Thread.currentThread().getName());
});
}
executor.shutdown();
}
}
是的,除了上述提到的四种常见的拒绝策略,Java中的ThreadPoolExecutor
还提供了另外一种拒绝策略:DiscardPolicy
。除此之外,您也可以自定义拒绝策略。
在此示例中,线程池最大线程数设置为1,工作队列长度也为1。当同时提交5个任务时,第一个任务能够被执行,但对于其余的任务,线程池将丢弃位于工作队列最前面(最旧的)的任务,并尝试再次提交新任务。
- 自定义拒绝策略
要自定义拒绝策略,您需要实现RejectedExecutionHandler
接口,并实现其中的rejectedExecution
方法,在该方法中定义自定义的拒绝逻辑。下面是一个示例:
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class CustomRejectionPolicyExample {
public static void main(String[] args) {
ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(1), new CustomRejectionPolicy());
// 提交5个任务,线程池无法处理超过1个任务,使用自定义的拒绝策略处理任务
for (int i = 1; i <= 5; i++) {
final int taskId = i;
executor.submit(() -> {
System.out.println("Task " + taskId + " executed by " + Thread.currentThread().getName());
});
}
executor.shutdown();
}
}
// 自定义拒绝策略实现RejectedExecutionHandler接口
class CustomRejectionPolicy implements ThreadPoolExecutor.RejectedExecutionHandler {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
if (!executor.isShutdown()) {
// 自定义拒绝策略的处理逻辑
System.out.println("Task rejected by custom rejection policy");
}
}
}
在此示例中,我们使用自定义的拒绝策略CustomRejectionPolicy
来处理线程池无法处理的任务。当提交任务时,线程池无法处理超过1个任务,因此拒绝策略将被触发,执行自定义的拒绝逻辑。
通过自定义拒绝策略,您可以根据具体需求来处理无法接收的任务。您可以在rejectedExecution
方法中实现自定义的处理逻辑,如记录日志、抛出异常或执行其他操作。
它们可以根据具体需求来选择适合的拒绝策略来处理线程池无法接收新任务的情况。