小伙伴问我为什么不用公共线程池,我说:这不是废话吗!

        2021-08-03,同事接手我写的代码, 看到我到处建线程池。很诧异的问:我建这么多线程干毛?逻辑核心数是固定的,你建这么多执行任务也不会变快,咋不用公共线程池?

        甚至想把我建的线程池都删掉!

        接着给我一顿分析:并行的线程数是固定的,一个任务的执行时间也是固定,得出结论耗时=任务数/并行数*单个任务执行时间;那么一个线程池跟多个线程池完全没有区别!

        然而事实真的是这样吗?超起键盘当场撸代码给他看。

  首先看单个线程池的情况:

public static final ThreadPoolExecutor pool =
      new ThreadPoolExecutor(20, 20, 5, TimeUnit.MINUTES, new ArrayBlockingQueue<>(20));

  public static void main(String[] args) throws InterruptedException {
    int task = 40;
    CountDownLatch latch = new CountDownLatch(task);
    long startTime = System.currentTimeMillis();
    //投递40个阻塞任务
    for (int i = 0; i < task; i++) {
      pool.execute(() -> {
        try {
          Thread.sleep(3000);
          latch.countDown();
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      });
    }
    latch.await();
    System.out.println("cost time:" + (System.currentTimeMillis() - startTime));
  }

执行结果如下:

 再看两个线程池执行40个任务,每个线程池执行20个:

  public static final ThreadPoolExecutor poolNo1 =
      new ThreadPoolExecutor(20, 20, 5, TimeUnit.MINUTES, new ArrayBlockingQueue<>(8));

  public static final ThreadPoolExecutor poolNo2 =
      new ThreadPoolExecutor(20, 20, 5, TimeUnit.MINUTES, new ArrayBlockingQueue<>(8));

  public static void main(String[] args) throws InterruptedException {
    int task = 40;
    CountDownLatch latch = new CountDownLatch(task);
    long startTime = System.currentTimeMillis();
    for (int i = 0; i < task/2; i++) {
      poolNo1.execute(() -> {
        try {
          Thread.sleep(3000);
          latch.countDown();
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      });
    }
    for (int i = 0; i < task/2; i++) {
      poolNo2.execute(() -> {
        try {
          Thread.sleep(3000);
          latch.countDown();
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      });
    }
    latch.await();
    System.out.println("cost time:" + (System.currentTimeMillis() - startTime));
  }

  执行结果如下:

        拿着数据,我对同事轻蔑的一笑,反问于他,这一拳20年的功力,你挡得住吗?

        同事见到结果立刻换了一副嘴脸向我求教。

        从未见过如此 厚 颜 无 耻 之人!

       

百度复制来的图片

原因其实很简单:一个线程池中的线程全部Blocked时,之后的任务只会进入阻塞队列,此时CPU空闲。而两个线程池时,当线程池1中的线程全部Blocked时,线程池2的线程会被调度。

直观的比较:一个线程池只有20个任务同时执行,两个线程池相当于40个任务同时执行快一倍也就理所当然了。

        以上时同种任务才分到了不同线程池,实际应用中很少遇到,更多时遇到不同的任务使用线程池

  一个线程池执行两种任务,一种耗时任务,一种空任务,先提交耗时任务,再提交空任务,统计空任务的耗时:

  public static final ThreadPoolExecutor pool =
      new ThreadPoolExecutor(20, 20, 5, TimeUnit.MINUTES, new ArrayBlockingQueue<>(20));

  public static void main(String[] args) throws InterruptedException {
    int task = 20;
    CountDownLatch latch = new CountDownLatch(task);
    long startTime = System.currentTimeMillis();
    //任务1
    for (int i = 0; i < task; i++) {
      pool.execute(() -> {
        try {
          Thread.sleep(3000);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      });
    }
    //任务2
    for (int i = 0; i < task; i++) {
      pool.execute(latch::countDown);
    }
    latch.await();
    System.out.println("cost time:"+(System.currentTimeMillis()-startTime));
  }

  执行结果:

 现在把耗时任务跟空任务分配到不同的线程池

  public static final ThreadPoolExecutor poolNo1 =
      new ThreadPoolExecutor(20, 20, 5, TimeUnit.MINUTES, new ArrayBlockingQueue<>(8));

  public static final ThreadPoolExecutor poolNo2 =
      new ThreadPoolExecutor(20, 20, 5, TimeUnit.MINUTES, new ArrayBlockingQueue<>(8));

  public static void main(String[] args) throws InterruptedException {
    int task = 20;
    CountDownLatch latch = new CountDownLatch(task);
    long startTime = System.currentTimeMillis();
    for (int i = 0; i < task; i++) {
      poolNo1.execute(() -> {
        try {
          Thread.sleep(3000);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      });
    }
    for (int i = 0; i < task; i++) {
      poolNo2.execute(latch::countDown);
    }
    latch.await();
    System.out.println("cost time:"+(System.currentTimeMillis()-startTime));
  }

  执行结果:

 

 提升简直不要太多。

ps:多线程池在Spring Cloud组件Hytrix限流策略中早有应用,不信我SC总要信一下的吧。

       

        Hystrix 采用了 Bulkhead Partition 舱壁隔离技术,来将外部依赖进行资源隔离,进而避免任何外部依赖的故障导致本服务崩溃。

        舱壁隔离,是说将船体内部空间区隔划分成若干个隔舱,一旦某几个隔舱发生破损进水,水流不会在其间相互流动,如此一来船舶在受损时,依然能具有足够的浮力和稳定性,进而减低立即沉船的危险。

        Hystrix 对每个外部依赖用一个单独的线程池,这样的话,如果对那个外部依赖调用延迟很严重,最多就是耗尽那个依赖自己的线程池而已,不会影响其他的依赖调用。

上面这段 copy来的 附链接https://blog.csdn.net/m0_37609579/article/details/100411060

ps:线程太多了也不好会线程饥饿

  • 1
    点赞
  • 0
    评论
  • 1
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

表情包
插入表情
评论将由博主筛选后显示,对所有人可见 | 还能输入1000个字符
©️2021 CSDN 皮肤主题: 游动-白 设计师:白松林 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值