java ThreadPoolExecutor 线程池构造方法参数:拒绝策略

说明

线程池有大小,当线程池不够承载时,就涉及到拒绝策略,有预定的策略,也可以自定义

拒绝处理的时机

  • 当线程数量达到 maxPoolSize ,且队列已经满了, 会采取拒绝策略

  • 当线程池调用 shutdown() 的时候, 会等待线程池的任务执行完毕, 再关闭线程池, 关闭线程池之前, 采取拒绝策略

  • shutdownNow(), 会立刻关闭, 并且停止执行任务. 并采取拒绝策略

拒绝策略分类

  • AbortPolicy:默认策略
  • CallerRunsPolicy
  • DiscardPolicy
  • DiscardOldestPolicy
  • 实现 RejectedExecutionHandler 接口,可自定义策略

AbortPolicy 中止策略(推荐)

功能:当触发拒绝策略时,直接抛出拒绝执行的异常,中止策略的意思也就是打断当前执行流程

默认策略

使用场景:适用一般场景

注意:要正确处理抛出的异常,会打断当前的执行流程

推荐使用该策略,中止后,由程序员处理

源码

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());
    }
}

例子

由于 corePoolSize、maximumPoolSize 是 1,也就是只能有 1 个线程运行

由于队列大小是 1,只能放 1 个线程
默认使用 AbortPolicy 拒绝策略

所以只能添加2个线程,添加第3个线程时,会抛异常

package ThreadPool;

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

public class 拒绝策略_抛异常 {
    public static void main(String[] args) {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                1,
                1,
                10,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue(1)
                );

        System.out.println("提交线程1");
        threadPoolExecutor.execute(new MyRun("1",threadPoolExecutor));

        System.out.println("提交线程2");
        threadPoolExecutor.execute(new MyRun("2",threadPoolExecutor));

        System.out.println("提交线程3");
        try {
            /*
             由于 corePoolSize、maximumPoolSize是1,队列大小是1
             也就是只能有1个线程运行,队列只能放1个线程,
             默认使用 AbortPolicy 拒绝策略
             所以添加第3个线程时,会抛异常
             */
            threadPoolExecutor.execute(new MyRun("3", threadPoolExecutor));
        }catch (Exception e){
            System.out.println("拒绝策略,抛出异常:"+e );
        }
        // 关闭线程池
        threadPoolExecutor.shutdown();
    }
    static class MyRun implements Runnable {
        String name;
        ThreadPoolExecutor threadPoolExecutor;

        public MyRun(String name, ThreadPoolExecutor threadPoolExecutor) {
            this.name = name;
            this.threadPoolExecutor = threadPoolExecutor;
        }

        @Override
        public void run() {
            System.out.println("----"+name+" 线程开始");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("===="+name+" 线程结束");
        }
    }
}

执行结果如下:

CallerRunsPolicy 策略

当触发拒绝策略时,只要线程池没有关闭,就由提交任务的当前线程处理。

使用场景:一般在不允许失败的、对性能要求不高、并发量较小的场景下使用,因为线程池一般情况下不会关闭,也就是提交的任务一定会被运行,但是由于是调用者线程自己执行的,当多次提交任务时,就会 阻塞后续任务执行,性能和效率自然就慢了。

源码

public static class CallerRunsPolicy implements RejectedExecutionHandler {

    public CallerRunsPolicy() { }

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

例子

package ThreadPool;

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

public class 拒绝策略_CallerRunsPolicy {
    public static void main(String[] args) {
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                1,
                1,
                10,
                TimeUnit.SECONDS,
                new LinkedBlockingQueue(1),
                new ThreadPoolExecutor.CallerRunsPolicy()
                );

        System.out.println("提交任务1");
        threadPoolExecutor.execute(new MyRun("1"));

        System.out.println("提交任务2");
        threadPoolExecutor.execute(new MyRun("2"));

        System.out.println("提交任务3");

        threadPoolExecutor.execute(new MyRun("3"));
        System.out.println("执行的末尾");
    }
    static class MyRun implements Runnable {
        String name;

        public MyRun(String name) {
            this.name = name;
        }

        @Override
        public void run() {
            System.out.println("----"+name+" 任务开始");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("===="+name+" 任务结束");
        }
    }
}

执行结果:

DiscardPolicy 丢弃策略

功能:丢弃这个任务,不触发任何动作

使用场景:如果提交的任务无关紧要,就可以使用该策略 。一般不用

源码

public static class DiscardPolicy implements RejectedExecutionHandler {

    public DiscardPolicy() { }

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

DiscardOldestPolicy 弃老策略

功能:如果线程池未关闭,就弹出队列头部的元素,然后尝试执行

使用场景:这个策略还是会丢弃任务,丢弃时也是毫无声息,但是特点是丢弃的是老的未执行的任务,而且是待执行优先级较高的任务。

源码

public static class DiscardOldestPolicy implements RejectedExecutionHandler {

    public DiscardOldestPolicy() { }

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

参考:
https://segmentfault.com/a/1190000040502271


原文出处:/show_1IX4d2qwGejV.html