Java中线程池拒绝策略——代码讲解

1、在使用ThreadPoolExecutor创建多线程时候,需要出入多个参数,如下:

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler) {

其中的RejectedExecutionHandler handler就是指定拒绝策略,是指当任务添加到线程池中被拒绝时采取的处理措施。当任务添加到线程池中之所以被拒绝,可能是由于:线程池异常关闭或者任务数量超过线程池的最大限制。线程池共包括4种拒绝策略,它们分别是:AbortPolicyCallerRunsPolicyDiscardOldestPolicyDiscardPolicy

AbortPolicy:当任务添加到线程池中被拒绝时,它将抛出 RejectedExecutionException 异常。是线程池默认的处理策略
CallerRunsPolicy当任务添加到线程池中被拒绝时,会在线程池当前正在运行的Thread线程池中处理被拒绝的任务。这种策略会降低对于新任务提交速度,影响程序的整体性能。另外,这个策略喜欢增加队列容量。如果您的应用程序可以承受此延迟并且你不能任务丢弃任何一个任务请求的话,你可以选择这个策略。(对比之下是最可靠的策略)。
DiscardOldestPolicy当任务添加到线程池中被拒绝时,线程池会放弃等待队列中最久的未处理任务,然后将被拒绝的任务添加到等待队列中。也即此策略将丢弃最早的未处理的任务请求。
DiscardPolicy 当任务添加到线程池中被拒绝时,线程池将丢弃被拒绝的任务。也即不处理新任务,直接丢弃掉。

 

2、DiscardPolicy 

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class DiscardPolicyDemo {

    private static final int THREADS_SIZE = 2;
    private static final int MAX_MUM_POOLSIZE = 4;
    private static final int CAPACITY = 2;

    public static void main(String[] args) throws Exception {

        // 创建线程池。
        ThreadPoolExecutor pool = new ThreadPoolExecutor(THREADS_SIZE, MAX_MUM_POOLSIZE, 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;
    }
    public void run() {
        try {
            System.out.println(this.name + " is running.");
            Thread.sleep(100);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

输出:

task-1 is running.
task-4 is running.
task-0 is running.
task-5 is running.
task-2 is running.
task-3 is running.

结果说明:可以发现一共打印出了6个任务的信息。

分析:corePoolSize设置为2,maxMumPoolSize设置为4,阻塞队列大小设置为2。所以,有2个任务会直接放入在线程池中运行,接下来会有2个任务放入阻塞队列中,又因为for循环创建了10个任务,所以当阻塞队列放满时,线程池还会创建2(maxMumPoolSize-corePoolSize)个线程来执行任务。后续会有4个任务被discard丢弃。所以一共执行了6个任务。

 

3、DiscardOldestPolicy 

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class DiscardOldestPolicyDemo {

    private static final int THREADS_SIZE = 2;
    private static final int MAX_MUM_POOLSIZE = 3;
    private static final int CAPACITY = 3;

    public static void main(String[] args) throws Exception {

        // 创建线程池。
        ThreadPoolExecutor pool = new ThreadPoolExecutor(THREADS_SIZE, MAX_MUM_POOLSIZE, 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;
    }
    public void run() {
        try {
            System.out.println(this.name + " is running.");
            Thread.sleep(200);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

输出结果:

task-0 is running.
task-1 is running.
task-5 is running.
task-7 is running.
task-8 is running.
task-9 is running.

结果说明:分析:corePoolSize设置为2,maxMumPoolSize设置为3,阻塞队列大小设置为3。前面2(0和1)个任务被线程直接执行,接下来三个(2、3、4)任务加入了队列中。此时阻塞队列满了。所以再创建1(maxMumPoolSize-corePoolSize)个线程执行任务5。再然后,继续提交的6,7,8,9会持续地往线程池中加入,此时因为队列已满,所以执行拒绝策略,删除队列中等待时间最久的任务。加入6,删除2,此时队列中是3,4,6。加入7,删除3,此时队列中是4,6,7。加入8,删除4,此时队列中是6,7,8。加入9,删除6,此时队列中剩下7,8和9。最终,当线程池中有空闲线程的时候,队列中的任务被执行,所以7,8和9任务被执行。

 

4、AbortPolicy 

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class AbortPolicyDemo {

    private static final int THREADS_SIZE = 2;
    private static final int MAX_MUM_POOLSIZE = 4;
    private static final int CAPACITY = 2;

    public static void main(String[] args) throws Exception {

        // 创建线程池。
        ThreadPoolExecutor pool = new ThreadPoolExecutor(THREADS_SIZE, MAX_MUM_POOLSIZE, 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;
    }
    public void run() {
        try {
            System.out.println(this.name + " is running.");
            Thread.sleep(200);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

输出结果:

task-0 is running.
task-1 is running.
task-4 is running.
task-5 is running.
java.util.concurrent.RejectedExecutionException: Task thread.MyRunnable@5e2de80c rejected from java.util.concurrent.ThreadPoolExecutor@1d44bcfa[Running, pool size = 4, active threads = 4, queued tasks = 2, completed tasks = 0]
    at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)
    at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
    at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)
    at thread.AbortPolicyDemo.main(AbortPolicyDemo.java:27)
task-2 is running.
task-3 is running.

​​​​​​结果说明:分析:corePoolSize设置为2,maxMumPoolSize设置为4,阻塞队列大小设置为2。前面2(0和1)个任务被线程直接执行,接下来两个(2、3)任务加入了队列中。此时阻塞队列满了。所以再创建2(maxMumPoolSize-corePoolSize)个线程执行任务4和5。再然后,继续提交的6,7,8,9会持续地往线程池中加入,此时因为队列已满,所以执行abort拒绝策略,执行abort策略会抛出异常。最终,当线程池中有空闲线程的时候,阻塞队列中的任务被执行,所以2和3任务被执行。

 

5、CallerRunsPolicy 

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class CallerRunsPolicyDemo {

    private static final int THREADS_SIZE = 2;
    private static final int MAX_MUM_POOLSIZE = 4;
    private static final int CAPACITY = 2;

    public static void main(String[] args) throws Exception {

        // 创建线程池。
        ThreadPoolExecutor pool = new ThreadPoolExecutor(THREADS_SIZE, MAX_MUM_POOLSIZE, 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;
    }
    public void run() {
        try {
            System.out.println(this.name + " is running.");
            Thread.sleep(100);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

输出结果:

task-1 is running.
task-6 is running.
task-4 is running.
task-0 is running.
task-5 is running.
task-7 is running.
task-2 is running.
task-3 is running.
task-8 is running.
task-9 is running.

结果说明:此策略是相对最可靠的策略,被提交的任务都会被执行,只是可能会出现一些延迟。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值