栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

线程池的三个方法、七个参数、四种拒绝策略

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

线程池的三个方法、七个参数、四种拒绝策略

线程池 1. 概述
  • 线程池做的工作主要是:控制运行的线程数量,处理过程中将任务放入队列,然后在线程创建后启动这些任务,如果线程数量超过了最大数量,超出数量的线程排队等候,等其他线程执行完毕,再从队列中取出任务来执行。
  • 线程池的主要特点:线程复用,控制最大并发数,管理线程。
  • 线程池的优势:
    • 降低资源消耗:通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
    • 提高响应速度:当任务到达时,任务可以不需要等待线程创建就能立即执行。
    • 提高线程的可管理性:线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性。使用线程池可以进行统一分配,调优和监控。
2. 三个方法
  • ExecutorService threadPool = Executors.newSingleThreadExecutor():创建单个线程

    • 案例:

      public class ThreadPoolTest1 {
          public static void main(String[] args) {
              //创建单个线程的线程池
              ExecutorService pool = Executors.newSingleThreadExecutor();
      
              try {
                  for (int i = 0; i < 20; i++) {
                      pool.execute(()->{
                          System.out.println(Thread.currentThread().getName() + " is OK!");
                      });
                  }
              } catch (Exception e) {
                  e.printStackTrace();
              } finally {
                  //关闭线程池
                  pool.shutdown();
              }
      
          }
      }
      

      结果:最多只有一个线程

  • ExecutorService threadPool = Executors.newFixedThreadPool(i):创建一个有i个线程的线程池(固定大小线程池)

  • 案例

    public class ThreadPoolTest2 {
        public static void main(String[] args) {
            //创建5个线程的线程池
            ExecutorService pool = Executors.newFixedThreadPool(5);
            try {
                for (int i = 0; i < 20; i++) {
                    pool.execute(()->{
                        System.out.println(Thread.currentThread().getName() + " is OK!");
                    });
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                //关闭线程池
                pool.shutdown();
            }
        }
    }
    

    结果:最多可以有五个线程

  • ExecutorService threadPool = Executors.newCachedThreadPool():可伸缩线程池,线程池根据需要可以扩容,遇强则强遇弱则弱

    • 案例

      public class ThreadPoolTest3 {
          public static void main(String[] args) {
              //创建单个线程的线程池
              ExecutorService pool = Executors.newCachedThreadPool();
      
              try {
                  for (int i = 0; i < 20; i++) {
                      pool.execute(()->{
                          System.out.println(Thread.currentThread().getName() + " is OK!");
                      });
                  }
              } catch (Exception e) {
                  e.printStackTrace();
              } finally {
                  //关闭线程池
                  pool.shutdown();
              }
          }
      }
      

  • 上述的三个创建线程池的方法有弊端,阿里巴巴java开发文档中也提出这样的约束:

9.3 七个参数
  • 上述的三个方法的源码中,我们不难发现,虽然我们没有传入参数或者只传入了一个参数,但是都会返回一个有七个参数的线程池。
  • 七个参数:
    • int corePoolSize:核心线程数。
    • int maximumPoolSize:最大线程数。表明线程中最多能够创建的线程数量,此值必须大于等于1。
    • long keepAliveTime:空闲的线程保留的时间,超时了还没有调用就会释放。
    • TimeUnit unit:空闲线程的保留时间单位。
    • BlockingQueue workQueue:阻塞队列,存储等待执行的任务。
    • ThreadFactory threadFactory:线程工厂:创建线程的,一般用默认值,不需要改动。
    • RejectedExecutionHandler handler:拒绝策略。
9.4 四个拒绝策略
  • 四种拒绝策略在ThreadPoolExecutor是四个内部类。

  • 当线程池中的线程不够用时,再去访问

  • AbortPolicy abortPolicy = new ThreadPoolExecutor.AbortPolicy();默认的

    • 该策略下,当任务添加到线程池中被拒绝时,它将直接丢弃任务,并抛出RejectedExecutionException异常

    • 案例

      public class PolicyTest1 {
          public static void main(String[] args) {
      
              ThreadPoolExecutor pool = new ThreadPoolExecutor(
                      2,//核心线程数
                      5,//最大线程数
                      3,//空闲存活时间
                      TimeUnit.SECONDS,//时间单位
                      new LinkedBlockingQueue<>(3),//阻塞队列
                      Executors.defaultThreadFactory(),//线程工厂
                      new ThreadPoolExecutor.AbortPolicy());//AbortPolicy拒绝策略
      
              //模拟大量并发的线程
              while (true){
      
                  pool.execute(()->{
                      System.out.println("queue="+pool.getQueue().size());
                      try {
                          TimeUnit.SECONDS.sleep(1);
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                  });
              }
          }
      }
      
    • 结果

  • DiscardPolicy discardPolicy = new ThreadPoolExecutor.DiscardPolicy();

    • 该策略下,当任务添加到线程池中被拒绝时,默认情况下它将直接丢弃任务,但不会抛出异常。
  • DiscardOldestPolicy discardOldestPolicy = new ThreadPoolExecutor.DiscardOldestPolicy();

    • 该策略下,当任务添加到线程池中被拒绝时,线程池会放弃等待队列中最旧的未处理任务(即最早进入队列的任务),然后尝试将被拒绝的任务添加到等待队列中。
  • CallerRunsPolicy callerRunsPolicy = new ThreadPoolExecutor.CallerRunsPolicy();

    • 该策略下,当线程池不够用时,任务将不进入线程池执行,由调用者线程去执行。如果执行程序已关闭,则会丢弃该任务。

    • 案例

      public class PolicyTest4 {
          public static void main(String[] args) {
      
              ThreadPoolExecutor pool = new ThreadPoolExecutor(
                      2,
                      5,
                      3,
                      TimeUnit.SECONDS,
                      new LinkedBlockingQueue<>(3),
                      Executors.defaultThreadFactory(),
                      new ThreadPoolExecutor.CallerRunsPolicy());//CallerRunsPolicy()拒绝策略
      
              //模拟大量并发的线程
              while (true){
                  pool.execute(()->{
                      System.out.println(Thread.currentThread().getName() + "->queue:" + pool.getQueue().size());
                      try {
                          TimeUnit.SECONDS.sleep(1);
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                  });
              }
          }
      }
      
    • 结果

9.5 自定义合适的线程池
  • CPU密集型:电脑的核数是几核就将线程池的最大线程数设为即;选择maximunPoolSize的大小
    • Runtime.getRuntime().availableProcessors():获取cpu核数
  • I/O密集型:I/O十分占用资源;I/O密集型就是判断我们程序中十分耗I/O的线程数量,大约是最大I/O数的一倍到两倍之间
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1031403.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号