java线程池的阻塞策略

一、线程池的阻塞策略主要有以下几种:

AbortPolicy:这是默认阻塞策略,当线程队列和空闲线程都无法处理新任务时,新任务提交会直接抛出异常RejectedExecutionException,该异常可以由调用者捕获。

CallerRunsPolicy:这个策略会尝试调节机制,既不抛弃任务也不抛出异常,而是将某些任务回退到调用者,由调用任务的线程来执行。

DiscardPolicy:这个策略会抛弃新提交的任务,不进行处理。

DiscardOldestPolicy:这个策略会抛弃队列中最后一个任务,然后执行新进来的任务。

自定义策略:除了上面提到的四种常见的拒绝策略(AbortPolicy、CallerRunsPolicy、DiscardPolicy和DiscardOldestPolicy),您也可以通过自定义实现RejectedExecutionHandler接口来定义自己的拒绝策略。

二、策略的举例说明

这些是线程池中常见的拒绝策略,它们用于处理在线程池已满时无法接收新任务的情况。下面我会给出这4种拒绝策略的例子:

  1. 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异常。

  1. 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个任务时,第一个任务能够被执行,但对于其余的任务,线程池将不会抛出异常,而是将任务交由提交线程来执行。

  1. 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个任务时,第一个任务能够被执行,但对于其余的任务,线程池将直接丢弃它们。

  1. 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个任务时,第一个任务能够被执行,但对于其余的任务,线程池将丢弃位于工作队列最前面(最旧的)的任务,并尝试再次提交新任务。

  1. 自定义拒绝策略
    要自定义拒绝策略,您需要实现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方法中实现自定义的处理逻辑,如记录日志、抛出异常或执行其他操作。

它们可以根据具体需求来选择适合的拒绝策略来处理线程池无法接收新任务的情况。

Java中,线程池是一种管理线程并发执行的机制,它提供了一种更高效、资源可重用的方式来组织任务执行。控制线程池主要有以下几个方面: 1. **大小限制**:线程池会设置最大线程数(`corePoolSize` 和 `maximumPoolSize`),当工作队列满且核心线程已全部运行时,如果新的请求到来,就会拒绝新任务,直到线程池中有空闲的线程可用。 2. **工作队列**:例如使用 `LinkedBlockingQueue` 或 `ArrayBlockingQueue`,用于存放等待执行的任务。一旦队列满且所有线程都在忙碌,处理策略可以是阻塞等待、丢弃任务或者用默认处理器(如单线程)执行。 3. **线程复用**:当线程完成任务并返回到线程池时,线程并不会立即结束,而是继续待命,等待下一轮任务分配。 4. **线程调度**:线程池中的线程可以根据设置的不同策略(如轮询、优先级、定时器等)进行调度。 5. **动态调整**:有些线程池API(如`ThreadPoolExecutor`)允许通过 `setCorePoolSize`、`setMaximumPoolSize` 等方法动态调整线程池大小。 6. **超时和守护线程**:可以配置线程等待队列的任务多久后放弃,并设置是否有守护线程(当主线程结束时,这些守护线程也会自动关闭)。 常见的Java线程池工具有`java.util.concurrent.ThreadPoolExecutor`和`java.util.concurrent.ExecutorService`,以及第三方库如Spring框架提供的`ThreadPoolTaskExecutor`。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@zcc@

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值