【线程池】四种拒绝策略

前言:

  1. 当我们初始化线程池时 ThreadPoolExecutor, 其中包含参数 RejectedExecutionHandler 拒绝策略。
  2. 当线程池中 线程数量等于最大线程数量 且 任务队列已满时,则会执行线程池会对新增加的任务执行拒绝策略。
  3. ThreadPoolExecutor 中默认帮我们实现了 4 中拒绝策略,我们也可以自己实现,需要 RejectedExecutionHandler 接口,并完成 rejectedExecution 方法。

源码展示:

  1. RejectedExecutionHandler 拒绝策略接口定义:
package java.util.concurrent;

/**
 * 拒绝策略 接口定义
 * 
 * @since 1.5
 * @author Doug Lea
 */
public interface RejectedExecutionHandler {

  /**
     * 拒绝任务是执行的方法
     * @param r 需要拒绝的任务
     * @param executor 当前线程池
     */
    void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
}
  1. ThreadPoolExecutor 4 个内部类实现了拒绝策略:
public class ThreadPoolExecutor extends AbstractExecutorService {

    // 省略代码

    /**
     * 由调用线程处理该任务
     */
    public static class CallerRunsPolicy implements RejectedExecutionHandler {

        public CallerRunsPolicy() { }

        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                r.run();
            }
        }
    }

    /**
     *  丢弃任务 并抛出RejectedExecutionException异常 【 默认 】
     */
    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());
        }
    }

    /**
     * 也是丢弃任务,但是不抛出异常
     */
    public static class DiscardPolicy implements RejectedExecutionHandler {

        public DiscardPolicy() { }

        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        }
    }

    /**
     * 丢弃队列最前面的任务,然后重新尝试执行任务
     */
    public static class DiscardOldestPolicy implements RejectedExecutionHandler {

        public DiscardOldestPolicy() { }

        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                // 丢弃队列最前面的任务
                e.getQueue().poll();
                // 重新尝试执行任务
                e.execute(r);
            }
        }
    }

}

应用示例:

示例代码:

public class Test1111 {

    public static void main(String[] args) {
        // 核心线程数
        int corePoolSize =1;
        // 最大线程数
        int maximumPoolSize =2;
        // 超过核心线程数时,线程的存活时间
        long keepAliveTime = 10;
        TimeUnit unit = TimeUnit.SECONDS;
        // 任务队列的大小【2】
        final LinkedBlockingQueue linkedBlockingQueue = new LinkedBlockingQueue(2);
        
        // 拒绝策略1: 由调用线程处理该任务
        RejectedExecutionHandler handler = new ThreadPoolExecutor.CallerRunsPolicy();
        // 拒绝策略2: 丢弃任务 并抛出RejectedExecutionException异常 【 默认 】
        //RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();
        // 拒绝策略 3 : 丢弃任务,但是不抛出异常
        // RejectedExecutionHandler handler = new ThreadPoolExecutor.DiscardPolicy ();
        // 拒绝策略 4 : 丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
        //RejectedExecutionHandler handler = new ThreadPoolExecutor.DiscardOldestPolicy();

        final ThreadPoolExecutor executorService  = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit,
                linkedBlockingQueue, handler);

        System.out.println("主线程名字:" + Thread.currentThread().getName());
        for (int i =1; i <=10; i++){
            final int finalI = i;
            try{
                executorService.execute(new Runnable() {
                    @Override
                    public void run() {
                    // 让线程执行的慢一些
                    try {
                        Thread.sleep(1000);
                        System.out.println("当前线程名字:" + Thread.currentThread().getName() +"; i ="+ finalI);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    }
                });
            }catch (Exception e){
                System.out.println("提交任务到线程池失败, ");
                e.printStackTrace();
            }
        }
        // 等待线程池 执行结束
        executorService.shutdown();
    }
}

通过设置核心线程数、最大线程数、以及任务队列的大小保证线程池无法处理这么多的任务。

  1. 拒绝策略1: 由调用线程处理该任务【CallerRunsPolicy】打印结果:
主线程名字:main
当前线程名字:main; i =5
当前线程名字:pool-1-thread-1; i =1
当前线程名字:pool-1-thread-2; i =4
当前线程名字:pool-1-thread-1; i =3
当前线程名字:pool-1-thread-2; i =2
当前线程名字:main; i =6
当前线程名字:pool-1-thread-1; i =7
当前线程名字:pool-1-thread-2; i =8
当前线程名字:main; i =9
当前线程名字:pool-1-thread-1; i =10
  1. 拒绝策略2: 丢弃任务 并抛出RejectedExecutionException异常 【 默认 AbortPolicy 】打印结果:
主线程名字:main
提交任务到线程池失败, 
java.util.concurrent.RejectedExecutionException: Task com.lot.threadpool.Test1111$1@6d6f6e28 rejected from java.util.concurrent.ThreadPoolExecutor@135fbaa4[Running, pool size = 2, active threads = 2, queued tasks = 2, completed tasks = 0]
	at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2047)
	at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:823)
	at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1369)
	at com.lot.threadpool.Test1111.main(Test1111.java:67)
提交任务到线程池失败, 
java.util.concurrent.RejectedExecutionException: Task com.lot.threadpool.Test1111$1@330bedb4 rejected from java.util.concurrent.ThreadPoolExecutor@135fbaa4[Running, pool size = 2, active threads = 2, queued tasks = 2, completed tasks = 0]
	at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2047)
	at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:823)
	at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1369)
	at com.lot.threadpool.Test1111.main(Test1111.java:67)
提交任务到线程池失败, 
java.util.concurrent.RejectedExecutionException: Task com.lot.threadpool.Test1111$1@4b67cf4d rejected from java.util.concurrent.ThreadPoolExecutor@135fbaa4[Running, pool size = 2, active threads = 2, queued tasks = 2, completed tasks = 0]
	at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2047)
	at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:823)
	at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1369)
	at com.lot.threadpool.Test1111.main(Test1111.java:67)
提交任务到线程池失败, 
java.util.concurrent.RejectedExecutionException: Task com.lot.threadpool.Test1111$1@12a3a380 rejected from java.util.concurrent.ThreadPoolExecutor@135fbaa4[Running, pool size = 2, active threads = 2, queued tasks = 2, completed tasks = 0]
	at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2047)
	at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:823)
	at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1369)
	at com.lot.threadpool.Test1111.main(Test1111.java:67)
提交任务到线程池失败, 
java.util.concurrent.RejectedExecutionException: Task com.lot.threadpool.Test1111$1@5cad8086 rejected from java.util.concurrent.ThreadPoolExecutor@135fbaa4[Running, pool size = 2, active threads = 2, queued tasks = 2, completed tasks = 0]
	at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2047)
	at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:823)
	at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1369)
	at com.lot.threadpool.Test1111.main(Test1111.java:67)
提交任务到线程池失败, 
java.util.concurrent.RejectedExecutionException: Task com.lot.threadpool.Test1111$1@61bbe9ba rejected from java.util.concurrent.ThreadPoolExecutor@135fbaa4[Running, pool size = 2, active threads = 2, queued tasks = 2, completed tasks = 0]
	at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2047)
	at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:823)
	at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1369)
	at com.lot.threadpool.Test1111.main(Test1111.java:67)
当前线程名字:pool-1-thread-1; i =1
当前线程名字:pool-1-thread-2; i =4
当前线程名字:pool-1-thread-1; i =2
当前线程名字:pool-1-thread-2; i =3
  1. 拒绝策略 3 : 丢弃任务,但是不抛出异常【DiscardPolicy】打印结果:
主线程名字:main
当前线程名字:pool-1-thread-2; i =4
当前线程名字:pool-1-thread-1; i =1
当前线程名字:pool-1-thread-1; i =3
当前线程名字:pool-1-thread-2; i =2
  1. 拒绝策略 4 : 丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)【DiscardOldestPolicy】打印结果:
主线程名字:main
当前线程名字:pool-1-thread-1; i =1
当前线程名字:pool-1-thread-2; i =4
当前线程名字:pool-1-thread-1; i =9
当前线程名字:pool-1-thread-2; i =10

END.

你可能感兴趣的:(#,并发)