Java线程池-自定义拒绝策略

Q: 什么时候需要使用拒绝策略呢?
A: 当任务数量超过系统实际承载能力的时候就要用到拒绝策略了,可以说它是系统超负荷运行的补救措施。简言之,就是线程用完,队列已满,无法为新任务服务,则需一套机制来合理的处理这些问题。

JDK 提供了四种内置拒绝策略,我们要理解并记住,有如下的四种:
1、DiscardPolicy: 默默丢弃无法处理的任务,不予任何处理
2、DiscardOldestPolicy: 丢弃队列中最老的任务, 尝试再次提交当前任务
3、AbortPolicy: 直接抛异常,阻止系统正常工作。
4、CallerRunsPolicy: 将任务分给调用线程来执行,运行当前被丢弃的任务,这样做不会真的丢弃任务,但是提交的线程性能有可能急剧下降。

以下是我们通常的使用方式:

int corePoolSize = 1;
int maximumPoolSize = 1;
BlockingQueue queue = new  ArrayBlockingQueue(1);
ThreadPoolExecutor pool = new ThreadPoolExecutor(corePoolSize,  maximumPoolSize,0, TimeUnit.SECONDS, queue ) ;
pool.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy ());
pool.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
pool.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());
pool.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());

但有时候我们需要对改接口进行扩展,来满足特别的需求就需要自定义了。

拒绝策略的接口实现
public interface RejectedExecutionHandler {
    void rejectedExecution(Runnable r, 
    ThreadPoolExecutor executor);
}
自定义拒绝策略的代码示例
public class RejectThreadPoolDemo {
    public static class MyTask implements Runnable {
        @Override
        public void run() {
            System.out.println(System.currentTimeMillis()
                    + ":Thread ID:" + Thread.currentThread().getId());
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String args[]) throws InterruptedException {
        MyTask myTask = new MyTask();

        ExecutorService executorService = new ThreadPoolExecutor(5, 5, 0L,
            TimeUnit.SECONDS, 
            new LinkedBlockingDeque(10),   
            Executors.defaultThreadFactory()
                , new RejectedExecutionHandler() {
            @Override
            public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
                //打印丢弃的任务
                System.out.println(r.toString() + " is discard");
            }
        });
        for (int i = 0; i < 100; i++) {
            executorService.submit(myTask);
            Thread.sleep(10);
        }
    }
}

上面自定义了一个线程池有5个常驻线程,最大线程数量也是5个,等待队列设为10,同时在这里自定义了拒绝策略,打印被丢弃的任务信息。

输出如下:
java.util.concurrent.FutureTask@1f32e575 is discard
java.util.concurrent.FutureTask@279f2327 is discard
java.util.concurrent.FutureTask@2ff4acd0 is discard
java.util.concurrent.FutureTask@54bedef2 is discard
1528709221737:Thread ID:10
1528709221752:Thread ID:11

思考:
  1. Java中有哪些无界队列和有界队列?
  2. 为什么生产上不能使用无界队列?

下一次分享让我们探讨一下有界、无界队列对ThreadPoolExcutor执行的影响,欢迎小伙伴们留言讨论~~

你可能感兴趣的:(Java多线程)