zoukankan      html  css  js  c++  java
  • 线程池

    线程池:三大方法、七大参数、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);
                }
            }
    

    线程池的大小如何设置

  • 相关阅读:
    “猫癣”集团借IE7新漏洞再掀风浪 狼人:
    研究人员在黑帽安全大会演示SSL攻击 狼人:
    猫癣病毒“躲猫猫” 移师广东东莞月入百万 狼人:
    Adobe两款软件存在缺陷 黑客可控制用户PC 狼人:
    安全观点:遭遇数据泄露破坏 损失的不只是金钱 狼人:
    McAfee报告称七成手机制造商认为手机安全至关重要 狼人:
    微软表示本月将发布五个Windows 7更新 狼人:
    Gmail电子邮件曝全球性故障 谷歌向用户道歉 狼人:
    Google Talk被黑客利用 发动钓鱼攻击 狼人:
    谷歌GMail邮件服务出现故障 部分服务已恢复 狼人:
  • 原文地址:https://www.cnblogs.com/liuzhidao/p/14243667.html
Copyright © 2011-2022 走看看