码迷,mamicode.com
首页 > 编程语言 > 详细

线程池

时间:2021-01-08 11:27:30      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:unless   uri   操作   pre   取出   大小   pool   lex   最大值   

线程池:三大方法、七大参数、4种拒绝策略

线程池的好处

1、降低资源的消耗
2、提高响应速度
3、方便管理
线程复用、可以控制最大并发数、管理线程

三大方法

ExecutorService threadPool = Executors.newSingleThreadExecutor();  //创建只有单个线程的线程池
ExecutorService threadPool = Executors.newFixedThreadPool(5);  //创建固定大小为5的线程池
 ExecutorService threadPool = Executors.newCachedThreadPool();  //创建一个可伸缩的线程池
  • 源码分析
public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,   //核心数和最大数都为1
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));  //阻塞队列的最大值为Integer.MAX_VALUE  这样会导致OOM,见阿里巴巴java开发者手册
    }

//阻塞队列代码
    public LinkedBlockingQueue() {
        this(Integer.MAX_VALUE);
    }

public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
        return new ThreadPoolExecutor(nThreads, nThreads,   //核心数和最大数都是传入的大小
                                      0L, TimeUnit.MILLISECONDS,
                                      new LinkedBlockingQueue<Runnable>(),  ////阻塞队列的最大值为Integer.MAX_VALUE  这样会导致OOM,见阿里巴巴java开发者手册
                                      threadFactory);
    }

    public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,   //核心数为0,最大值约为21亿 (会导致OOM ,见阿里巴巴java开发者手册)
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

七大参数

观察上面的三种方法,发现其本质都是使用ThreadPoolExecutor类创建线程池,要了解这个类,就需要知道线程池的七大参数


public ThreadPoolExecutor(int corePoolSize,  //核心线程池大小
                              int maximumPoolSize,                 //最大线程池大小
                              long keepAliveTime,                     //超时了没有人调用就会释放
                              TimeUnit unit,                                 // 超时单位
                              BlockingQueue<Runnable> workQueue,  //阻塞队列
                              ThreadFactory threadFactory,                   //线程工厂:创建线程的,一般不用动
                              RejectedExecutionHandler handler) {          //拒绝策略
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.acc = System.getSecurityManager() == null ?
                null :
                AccessController.getContext();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

注意:上面介绍三种方法时,说明了会产生OOM,所以必须要使用ThreadPoolExecutor来创建线程池
技术图片

线程池触发拒绝策略的时机

线程池有三个重要的参数 核心线程数 最大线程数 阻塞队列,线程池触发拒绝策略需要这三个参数总体协调,而不是简单超过了最大线程数就触发。

当提交的任务数大于corePoolSize(核心线程数)时,会优先放入到阻塞队列中,只有填满了阻塞队列后,才会判断当前运行的任务是否大于maxPoolSize(线程最大数),小于时会新建线程进行处理。大于时就会触发拒绝策略。总结就是 当提交的任务数 大于 (maxPoolSize + queueCapacity(阻塞队列)) 时就会触发线程池的拒绝策略

四种拒绝策略

  • AbortPolicy (终止策略)
    简单粗暴,直接抛出拒绝异常,这也是默认的拒绝策略
public static class AbortPolicy implements RejectedExecutionHandler {
        /**
         * Creates an {@code AbortPolicy}.
         */
        public AbortPolicy() { }

        /**
         * Always throws RejectedExecutionException.
         *
         * @param r the runnable task requested to be executed
         * @param e the executor attempting to execute this task
         * @throws RejectedExecutionException always
         */
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            throw new RejectedExecutionException("Task " + r.toString() +
                                                 " rejected from " +
                                                 e.toString());
        }
    }
  • CallerRunsPolicy (调用者执行策略)
    如果线程池未关闭,则会在调用者线程中执行新任务,这会导致主线程提交线程性能变慢
 public static class CallerRunsPolicy implements RejectedExecutionHandler {
        /**
         * Creates a {@code CallerRunsPolicy}.
         */
        public CallerRunsPolicy() { }

        /**
         * Executes task r in the caller‘s thread, unless the executor
         * has been shut down, in which case the task is discarded.
         *
         * @param r the runnable task requested to be executed
         * @param e the executor attempting to execute this task
         */
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                r.run();
            }
        }
    }
  • DiscardPolicy (丢弃策略)
    不做任何操作,直接丢弃。
 public static class DiscardPolicy implements RejectedExecutionHandler {
        /**
         * Creates a {@code DiscardPolicy}.
         */
        public DiscardPolicy() { }

        /**
         * Does nothing, which has the effect of discarding task r.
         *
         * @param r the runnable task requested to be executed
         * @param e the executor attempting to execute this task
         */
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        }
    }
  • DiscardOldestPolicy(丢弃老任务策略)
    抛弃最老的任务,就是从队列取出最老的任务,然后放入新的任务执行。
 public static class DiscardOldestPolicy implements RejectedExecutionHandler {
        /**
         * Creates a {@code DiscardOldestPolicy} for the given executor.
         */
        public DiscardOldestPolicy() { }

        /**
         * Obtains and ignores the next task that the executor
         * would otherwise execute, if one is immediately available,
         * and then retries execution of task r, unless the executor
         * is shut down, in which case task r is instead discarded.
         *
         * @param r the runnable task requested to be executed
         * @param e the executor attempting to execute this task
         */
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                e.getQueue().poll();
                e.execute(r);
            }
        }

线程池的大小如何设置

线程池

标签:unless   uri   操作   pre   取出   大小   pool   lex   最大值   

原文地址:https://www.cnblogs.com/liuzhidao/p/14243667.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!