Java并发编程(7)-ThreadPoolExecutor的饱和策略


更多关于Java并发编程的文章请点击这里:Java并发编程实践(0)-目录页


本文将介绍ThreadPoolExecutor的饱和策略以及ThreadPoolExecutor的扩展方法;当线程充满了ThreadPool的有界队列时,饱和策略开始起作用。饱和策略可以理解为队列饱和后,处理后续无法入队的任务的策略。在JDK中预先提供了几种饱和策略,ThreadPoolExecutor可以通过调用setRejectedExecutionHandler来修改饱和策略。ThreadPoolExecutor在设计的时候就支持扩展其方法,主要为前处理beforeExecute、后处理afterExecute`以及执行完毕处理terminated。

一、ThreadPoolExecutor的饱和策略

1.1、什么是饱和策略

当线程充满了ThreadPool的有界队列时,饱和策略开始起作用。**饱和策略可以理解为队列饱和后,处理后续无法入队的任务的策略。**在JDK中预先提供了几种饱和策略,ThreadPoolExecutor可以通过调用setRejectedExecutionHandler来修改饱和策略。

1.2、Abort策略

ThreadPoolExecutor的 默认策略,新任务提交时直接抛出未检查的异常RejectedExecutionException,该异常可由调用者捕获。

@Test
    public void testPolicy() {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(5,
                5,
                0,
                TimeUnit.MICROSECONDS,
                new ArrayBlockingQueue<Runnable>(5));
        //设置饱和策略为AbortPolicy
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
        //测试
        for (int i = 1; i <= 11; i++) {

            int count = i;
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    //模拟耗时操作
                    for (int j = 0; j < 100000; j++) {
                        //...
                    }
                    System.out.println("这是第" + count + "个线程在执行任务----" + Thread.currentThread().getName());
                }
            });


        }
    }

运行后,由于设置了核心池线程数为5,有界队列能存储的线程数为5,故一共只有10个任务能被执行,多余的那1个任务将被以异常的形式抛出。
在这里插入图片描述

1.3、CallerRuns策略

既不抛弃任务也不抛出异常,而是将某些任务回退到调用者,让调用者去执行它。

@Test
   public void testPolicy() {
       ThreadPoolExecutor executor = new ThreadPoolExecutor(5,
               5,
               0,
               TimeUnit.MICROSECONDS,
               new ArrayBlockingQueue<Runnable>(5));
       //设置饱和策略为AbortPolicy
       executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
       //测试
       for (int i = 1; i <= 11; i++) {

           int count = i;
           executor.execute(new Runnable() {
               @Override
               public void run() {
                   //模拟耗时操作
                   for (int j = 0; j < 100000; j++) {
                       //...
                   }
                   System.out.println("这是第" + count + "个线程在执行任务----" + Thread.currentThread().getName());
               }
           });


       }
   }

从执行结果中可以看到,多出来的那11个任务被executor的调用者main主线程执行。
在这里插入图片描述

1.4、Discard策略

多余的任务被抛弃,不执行。

@Test
   public void testPolicy() {
       ThreadPoolExecutor executor = new ThreadPoolExecutor(5,
               5,
               0,
               TimeUnit.MICROSECONDS,
               new ArrayBlockingQueue<Runnable>(5));
       //设置饱和策略为DiscardPolicy
       executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
       //测试
       for (int i = 1; i <= 11; i++) {

           int count = i;
           executor.execute(new Runnable() {
               @Override
               public void run() {
                   //模拟耗时操作
                   for (int j = 0; j < 100000; j++) {
                       //...
                   }
                   System.out.println("这是第" + count + "个线程在执行任务----" + Thread.currentThread().getName());
               }
           });


       }
   }

在这里插入图片描述

1.5、DiscardOldest策略

抛弃工作队列中的旧任务,然后尝试提交新任务执行。

@Test
   public void testPolicy() {
       ThreadPoolExecutor executor = new ThreadPoolExecutor(5,
               5,
               0,
               TimeUnit.MICROSECONDS,
               new ArrayBlockingQueue<Runnable>(5));
       //设置饱和策略为DiscardOldestPolicy
       executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());
       //测试
       for (int i = 1; i <= 11; i++) {

           int count = i;
           executor.execute(new Runnable() {
               @Override
               public void run() {
                   //模拟耗时操作
                   for (int j = 0; j < 100000; j++) {
                       //...
                   }
                   System.out.println("这是第" + count + "个线程在执行任务----" + Thread.currentThread().getName());
               }
           });


       }
   }

从执行结果可以看出,第11个任务被执行了,说明工作队列中的最旧任务被抛弃,执行了这个新的任务。
在这里插入图片描述

二、ThreadPoolExecutor的扩展方法

ThreadPoolExecutor在设计的时候就支持扩展其方法,主要为前处理beforeExecute后处理afterExecute以及执行完毕处理terminated

自定义的ThreadPoolExecutor:

public class MyThreadPoolExecutor extends ThreadPoolExecutor {
    public MyThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
    }

    public MyThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
    }

    public MyThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
    }

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


    @Override
    protected void beforeExecute(Thread t, Runnable r) {
        super.beforeExecute(t, r);
        //before execute....
        System.out.println("before execute....");
    }

    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        super.afterExecute(r, t);
        //after execute....
        System.out.println("after execute....");
    }

    @Override
    protected void terminated() {
        super.terminated();
        //terminated
        System.out.println("terminated");
    }
}

在这里插入图片描述

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页