首页 > 其他分享 >阿里巴巴不推荐使用JDK自带工具类创建线程池的原因

阿里巴巴不推荐使用JDK自带工具类创建线程池的原因

时间:2022-10-26 09:37:07浏览次数:44  
标签:10 JDK Executors 创建 线程 new 自带 执行

目录

一、线程和线程池的关系

    /**
     * 使用list来创建100个线程 花费时间 220 ms
     *
     * @throws InterruptedException
     */
    private static void createThreadPoolForList() throws InterruptedException {
        List<Thread> threadPool = new ArrayList<>(100);
        long start = System.currentTimeMillis();
        logger.info("创建线程池开始");
        for (int i = 0; i < 100; i++) {
            Thread thread = new Thread(() -> {
                try {
                    TimeUnit.SECONDS.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }, "t" + i);
            thread.start();
            threadPool.add(thread);
            TimeUnit.MICROSECONDS.sleep(1);
        }
        logger.info("创建100个线程的线程池花费时间:{} ms",System.currentTimeMillis()-start);
    }

创建100个线程花费了220ms,一个线程大概是2.2ms。但是任务执行,可能只是在1ms,那么这样子以来就得不偿失了。

所以临时创建线程来执行任务是不划算的。

而且在创建线程期间,如果存在大量的创建线程,会导致频繁的用户态到内核态的切换。非常消耗性能。

所以为此切记不要在每次执行任务的时候而来创建线程池执行任务。

而对于已经创建好了线程来说,我们可以重复利用这里的线程,让线程为具体执行的业务而来执行对应的代码。不需要每次执行任务而来创建一个线程来执行,高效利用已经存在了的线程。

线程复用

利用已经存在了的线程来执行任务,那么线程池中的一个线程可能是执行了多个任务。所以我们从打印上效果上来看,就可以看到具体的信息。

二、阿里巴巴为什么不推荐使用JDK自带工具类创建线程池

newCachedThreadPool因为大小不确定而占用内存;newFixedThreadPool和newSingleThreadExecutor因为队列占用CPU资源;所以不推荐

ExecutorService executorService1 = Executors.newCachedThreadPool();//最快
ExecutorService executorService2 = Executors.newFixedThreadPool(10);//慢
ExecutorService executorService3 = Executors.newSingleThreadExecutor();//最慢


// 创建一个定长线程池,支持定时及周期性任务执行
// 我觉得是不支持自定义化操作
Executors.newScheduledThreadPool(10);

Executors.newCachedThreadPool()

原理需要看下对应的源码分析

public static ExecutorService newCachedThreadPool() {
        return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                      60L, TimeUnit.SECONDS,
                                      new SynchronousQueue<Runnable>());
    }

没有核心线程,只有Integer.MAX_VALUE个非核心线程。每进来一个核心线程,就会进入到队列中来,但是队列只能够处理1个。处于忙碌状态,所以只能够创建非核心线程来进行处理。

弊端:不断的创建对象,会导致内存溢出

Executors.newFixedThreadPool(10)

进入newFixedThreadPool(10)方法,方法传递了一个参数10,可以看到里面调用了原生创建线程池方法ThreadPoolExecutor,10通过源码我们可以看到赋值了核心线程和最大线程数,证明有10个核心线程来执行此任务,最大线程也是10,就没有临时线程了,所有任务全部用这10个核心线程来执行,因为线程有限,所以执行速度较慢。

public static ExecutorService newFixedThreadPool(int nThreads) {    
return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}

没有临时线程,只有核心线程和非核心线程。核心队列处理不过来,就只能够放入到队列中来。

弊端:假设我们设置了线程数为一个预测并发最高值,但是在双十一当天并发比原来的高的多,线程处理不过来,请求任务放在队列中,过多导致CPU突增,产生任务尖刺。

Executors.newSingleThreadExecutor()

进入newSingleThreadExecutor()方法,可以看到里面调用了原生创建线程池方法ThreadPoolExecutor,传递了不同的参数,通过源码可以看到核心线程和最大线程为1,证明只有一个核心线程,没有临时线程,因为线程只有1个,所有执行速度最慢。

public static ExecutorService newSingleThreadExecutor() {
        return new FinalizableDelegatedExecutorService
            (new ThreadPoolExecutor(1, 1,
                                    0L, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue<Runnable>()));
    }

弊端:当请求任务增量特别大的时候,由于线程数为1,请求任务全部在队列里面,会导致内存溢出

所以阿里开发手册上写了不建议使用Executors,Java常用的线程池弊端在上面也介绍了,解决方法是我们进行自定义线程池,设置线程数。

标签:10,JDK,Executors,创建,线程,new,自带,执行
From: https://www.cnblogs.com/likeguang/p/16827134.html

相关文章

  • 线程的查看方式&运行原理
    观察多个线程同时运行主要是理解交替执行谁先谁后,不由我们控制查看进程线程的方法windows任务管理器可以查看进程和线程数,也可以用来杀死进程tasklist查看进程......
  • Linux 安装 jdk
    目录1.下载jdk82.源码包解压3.配置jdk环境变量4.测试是否安装成功操作系统:Centos6.464位工具:Xftp5、Xshell51.下载jdk8方法一:官网手动下载下载Linux环境下的jdk......
  • Java多线程(3):ThreadPool(下)
    您好,我是湘王,这是我的博客园,欢迎您来,欢迎您再来~ 除了可以通过ThreadPoolExecutor自定义线程池外,同StreamAPI中的Collectors一样,多线程里的Executors类也提供了一组相关......
  • 多线程应用——双色球
    通过多线程实现双色球选号,要求:1、红球从01到33不能有重复;2、蓝球从1到16效果如下:    难点: 1、多线程实现 2、跨线程修改UI 3、线程安全(红球不能有重......
  • linux下安装jdk步骤
    inux下安装jdk,都是下载压缩包解压,配置环境变量等步骤。这里记录一下安装1.8版本的过程,方便下次查阅。1.创建java安装目录mkdir-pjava/jdk2.下载jdk压缩包切换到jdk目......
  • java dump 线程命令 jstack PID >> mydumps.dump
    一、背景Java应用怎么通过方法定位到代码的具体步骤,下面通过一个具体的例子来说明。二、分析步骤使用TOP命令找到谁在消耗CPU比较高的进程,例如:pid=1232使用top-p......
  • 《上下文切换 —— 进程上下文切换、线程上下文切换、中断上下文切换》
    一文带你深入理解LinuxCPU上下文切换(超详细~)-哔哩哔哩(bilibili.com)(37条消息)Linux进程上下文概念详解_奔跑的码农的博客-CSDN博客_linux进程上下文(37条消息)Li......
  • jdk和jre(jdk和jre的关系)
    jdkjre分别指的是什么东西啊?java软件包中主要有两部分:jdk,jre。前者就是开发java程序是所用的JDK,jre是javaruntimeenvirment的简称,包括javaruntimeenvironment和java......
  • Windows下查看电脑的CPU个数,核心数,线程数
    总核数=物理CPU个数X每颗物理CPU的核数总逻辑CPU数=物理CPU个数X每颗物理CPU的核数X超线程数查看物理CPU的个数:在cmd命令中输入“systeminfo”主机名:......
  • Java多线程(3):ThreadPool(中)
    您好,我是湘王,这是我的51CTO博客,欢迎您来,欢迎您再来~线程池是个神器,用得好会非常地方便。本来觉得线程池的构造器有些复杂,即使讲清楚了对今后的用处可能也不太大,因为有一些Jav......