根据阿里巴巴的开发手册,在并发编程部分有一条:线程池不允许使用Executors创建,而是使用ThreadPoolExecutor通过源码分析分析禁用原因。首先感谢大家边造楼边看这篇文章。通过阅读本文,您将了解:定义线程池Executors创建线程池的几种方式ThreadPoolExecutor对象线程池执行任务逻辑与线程池参数关系Executors创建返回ThreadPoolExecutor对象OOM异常测试如何定义线程池参数如果你只是想要知道原因,请参阅下面的线程池定义来管理一组工作线程。通过线程池多路复用线程有以下好处:减少资源创建=>减少内存开销,创建线程占用内存减少系统开销=>创建线程耗时,延迟处理请求,提高稳定性=>避免无限线程创建引起的OutOfMemoryError[简称OOM]Executors根据返回对象类型创建线程池创建线程池可以分为三类:创建并返回一个ThreadPoolExecutor对象创建并返回一个ScheduleThreadPoolExecutor对象创建并返回一个ForkJoinPool对象仅本文讨论创建和返回ThreadPoolExecutor对象ThreadPoolExecutor对象在创建线程池方法之前引入Executors引入ThreadPoolExecutor,因为这些创建线程池的静态方法返回ThreadPoolExecutor对象,和手动创建ThreadPoolExecutor对象的区别是我们不需要通过par米到构造函数。ThreadPoolExecutor有四个构造函数,但最终调用都是一样的:publicThreadPoolExecutor(intcorePoolSize,intmaximumPoolSize,longkeepAliveTime,TimeUnitunit,BlockingQueueworkQueue,ThreadFactorythreadFactory,RejectedExecutionHandlerhandler)构造函数参数说明:corePoolSize=>线程池核心线程数maximumPoolSize=>线程池的最大数量keepAliveTime=>空闲线程生存时间单位=>时间单位workQueue=>线程池使用的缓冲队列threadFactory=>线程池创建线程使用的工厂处理程序=>线程池对被拒绝任务的处理策略线程池执行任务逻辑与线程池参数的关系执行逻辑说明:判断核心线程数是否满。核心线程数的大小与corePoolSize参数有关。如果未满,则创建线程执行任务。如果核心线程池已满,则判断队列是否已满,队列是否满与workQueue参数有关,如果未满则加入队列,如果队列满则判断线程池是否满,线程池是否满与maximumPoolSize参数有关,如果未满,则创建线程执行任务,如果线程池已满,则使用拒绝策略处理无法执行的任务。拒绝策略和处理程序参数与Executors创建和返回ThreadPoolExecutor对象有关。执行器创建并返回ThreadPoolExecutor对象。共有三种方法:Executors#newCachedThreadPool=>创建可缓存线程池Executors#newSingleThreadExecutor=>创建单线程线程池Executors#newFixedThreadPool=>创建定长线程池Executors#newCachedThreadPool方法publicstaticExecutorSservicenewCachedThreadPool(){returnnewThreadPoolExecutor(0,Integer.MAX_VALUE,60L,TimeUnit.SECONDS,newSynchronousQueue());}CachedThreadPool是根据需要创建新线程的线程池corePoolSize=>0,核心线程池的个数为0maximumPoolSize=>Integer.MAX_VALUE,可以认为最大线程数是无限的keepAliveTime=>60Lunit=>secondsworkQueue=>SynchronousQueue提交任务时,corePoolSize为0,不创建核心线程。SynchronousQueue是一个不存储元素的队列。可以这样理解,队列总是满的,所以最终还是会创建非核心线程来执行任务,非核心线程空闲60秒就会被回收。因为Integer.MAX_VALUE很大,可以认为可以无限创建线程,在资源有限的情况下很容易造成OOM异常Runnable>()));}SingleThreadExecutor是单线程线程池,只有一个核threadcorePoolSize=>1,核心线程池数量为1maximumPoolSize=>1,只能创建一个非核心线程keepAliveTime=>0Lunit=>SecondsworkQueue=>LinkedBlockingQueue当任务提交时,一个核心线程会首先创建以执行任务。如果核心线程数超过了数量,就会被放入队列,因为LinkedBlockingQueue是一个长度为Integer.MAX_VALUE的队列,可以认为是无界Queue,所以可以无限制的向队列中插入任务,这在资源有限的情况下很容易导致OOM异常。同时因为无界队列,maximumPoolSize和keepAliveTime参数会失效,根本不会创建非核心线程。Executors#newFixedThreadPoolmethodpublicstaticExecutorServicenewFixedThreadPool(intnThreads){returnnewThreadPoolExecutor(nThreads,nThreads,0L,TimeUnit.MILLISECONDS,newLinkedBlockingQueue());}FixedThreadPool是固定核心线程的线程池,固定核心线程数由用户给corePoolSize=>1,核心线程池数量为1maximumPoolSize=>1,只能创建一个非核心线程keepAliveTime=>0Lunit=>secondworkQueue=>LinkedBlockingQueue和SingleThreadExecutor类似,唯一不同的是核心线程数不同,因为使用了LinkedBlockingQueue,当资源有限时容易导致OOM异常总结:FixedThreadPool和SingleThreadExecutor=>允许的请求队列长度为Integer.MAX_VALUE,可能会累积大量请求,从而导致OOM异常CachedThreadPool=>允许的线程数created是Integer.MAX_VALUE,可能会创建大量的Thread,导致OOM异常。这就是为什么禁止使用Executors创建线程池,而是推荐自己创建ThreadPoolExecutors的原因。OOM异常测试理论上会导致OOM异常,必须测试一波验证。前面的语句:测试类:TaskTest。javapublicclassTaskTest{publicstaticvoidmain(String[]args){ExecutorServicees=Executors.newCachedThreadPool();inti=0;while(true){es.submit(newTask(i++));}}}使用Executors创建的CachedThreadPool到线程池加入无限线程,把JVM内存调小一点再开始测试课,不然很容易跑出电脑【别问我为什么知道,铁打甜!!!】,在idea中:Run->EditConfigurationsJVM参数说明:-Xms10M=>JavaHeap内存初始化值-Xmx10M=>JavaHeap内存最大值运行结果:Exception:java.lang.OutOfMemoryErrorthrownfromtheUncaughtExceptionHandlerinthread"main"DisconnectedfromthetargetVM,address:'127.0.0.1:60416',transport:'socket'当创建超过3w个线程时开始报OOM错误线程池不一样如何定义线程池参数CPU-intensive=>Thesizeof线程池建议为CPU个数+1,CPU个数可根据Runtime.availableProcessors方法获取IO-intensive=>CPU个数*CPU利用率*(1+线程等待时间/线程CPUtime)hybrid=>将任务分为CPU密集型和IO密集型,然后使用不同的线程池来处理,这样每个线程池就可以根据各自的工作负载调整阻塞队列=>推荐使用有界队列.有界队列有助于避免资源耗尽。拒绝策略=>默认采用AbortPolicy拒绝策略,直接在程序中抛出RejectedExecutionException【因为是运行时异常,不强制捕获】,这种处理方式不够优雅。处理拒绝的策略有几种建议:在程序中捕获RejectedExecutionException,在捕获异常的同时处理任务。默认拒绝策略使用CallerRunsPolicy拒绝策略。这种策略会将任务交给调用execute的线程[一般是主线程]。这时主线程会在一段时间内无法提交任何任务,让工作线程处理执行。任务。此时提交的线程会保存在TCP队列中,TCP队列满了会影响客户端。这是一种温和的性能降低自定义拒绝策略,只需要实现RejectedExecutionHandler接口即可。如果任务不是特别重要,使用DiscardPolicy也可以丢弃带有DiscardOldestPolicy拒绝策略的任务。如果使用Executors的静态方法创建ThreadPoolExecutor对象,可以使用Semaphore来限制任务的执行,避免OOM异常。