铜陵网站建设公司,代码给wordpress添加图片不显示,定兴网站建设,wordpress公众号验证码目录
ThreadPoolExecutor的构造函数 关于线程池的一些补充
线程池运行原理分析
概念原理解释
整个流程图如下#xff1a;
一点补充 创建线程池主要有两种方式#xff1a; 通过Executor工厂类创建#xff0c;创建方式比较简单#xff0c;但是定制能力有限通过ThreadPoo…
目录
ThreadPoolExecutor的构造函数 关于线程池的一些补充
线程池运行原理分析
概念原理解释
整个流程图如下
一点补充 创建线程池主要有两种方式 通过Executor工厂类创建创建方式比较简单但是定制能力有限通过ThreadPoolExecutor创建创建方式比较复杂但是定制能力强但我们一般不建议使用Executor工厂类来进行线程的创建。
原因如下 Executor提供的很多方法默认使用的都是无界的LinkedBlockingQueue在高负载情况下无界队列很容易导致OOM——OOM 全称 “Out Of Memory”表示内存耗尽。当 JVM 因为没有足够的内存来为对象分配空间并且垃圾回收器也已经没有空间可回收时就会抛出这个错误。 那么一旦出现了OOM就会导致所有的请求都无法处理这个是致命问题。所有要尽量避免使用无界队列——》即慎用Executor来创建线程 那么下面让我们详细了解推荐使用的ThreadPoolExecutor这个核心工具类。
ThreadPoolExecutor的构造函数 ThreadPoolExecutor 的构造函数非常复杂如下面代码所示这个最完备的构造函数有 7 个参数。
ThreadPoolExecutor (int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueueRunnable workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler) 一起来看看这7个参数的含义分别是什么吧 corePoolSize 核心线程数就是该线程池保有的最下线程数 maximumPoolSize 最大线程数 keepAliveTime 和unit 我们首先要知道线程分为空闲阻塞等待中和忙碌执行任务两种状态当一个线程空闲了较长时间同时此时线程池子中的线程数目大于核心线程数目corePoolSize该线程就会被销毁回收 keepAlive和unit就是用来衡量空闲时间的当空闲时间大于keepAliveTime时候unit是keepAliveTime是时间单位同时线程数目大于corePoolSize时该线程就会被注销 workQueue 工作队列一个阻塞队列用来存放可执行任务Runnable Task threadFactory 通过这个参数你可以自己定义如何创建线程比如你可以给线程指定一个有意义名称 handler 通过这个参数你可以自定义任务的拒绝策略如果线程池中的线程都在忙碌并且工作队列也满了前提工作队列是有界队列此时当有一个新的任务添加进来提交任务线程池会拒绝接收。 至于拒绝的策略你可以通过handler这个参数来指定ThreadPoolExecutor以及提供了以下四种策略。 CallerRunsPolicy提交任务的线程自己去执行该任务AbortPolicy默认的拒绝策略会throw RejectedExecutorException—》这是个运行时异常编辑器不强制catch、容易忽略开发人员要谨慎使用可以自己定义自己的拒绝策略DiscardPolicy直接丢弃任务没人任何异常输出DiscardOldestPolicy丢弃最古老的任务其实就是把最早进入任务队列workQueue的任务给丢弃掉然后把新任务添加到任务队列中。关于线程池的一些补充
线程是一个重量级的对象应该避免频繁创建和销毁
目前业界线程池的设计普遍采用的都是生产者 - 消费者模式。 线程池的使用方是生产者线程池本身是消费者 比如上面我们的任务队列workQueue生产的Runnable任务就放到了该队列中这些任务供线程池中的线程执行消费 线程池运行原理分析
概念原理解释
1、创建一个线程池当此时还没有任务提交的时候阻塞队列workQueue为空的时候此时默认线程池中是没有线程的当然了此时也可以调用prestartThread方法来预先创建一个核心线程 2、当线程池里面还没有线程或者是线程池中存活的线程小于核心线程数corePoolSize的时候每新提交一个任务线程池就会专门创建一个新的线程来处理刚刚提交的任务阻塞队列workQueue中的Runnable任务。
此时线程池中的线程会一直存活着即使线程是空闲的甚至空闲时间超过了keepAliveTime 线程也不会销毁此时线程池中的线程小于核心线程数corePoolSize)
那么这个时候线程就只能等任务队列中什么时候有可执行的任务了Runnable task) 才会重写开始执行变得忙碌起来在此之前线程一直是阻塞在那里的——》这也是为什么线程池队列用的是阻塞队列 3、当线程池中的线程数等于线程核心数corePoolSize同时任务队列有空间此时当再有新的任务提交的时候该任务会被放到任务队列中(workQueue排队等待执行。而不会在新创建一个线程来执行刚刚提交的任务。
此时之前创建的线程并不会被注销而是会不断的去拿阻塞队列中的任务当任务队列中的任务为空的时候线程会阻塞直到有任务Runnable Task被放进任务队列中。
这也是为什么线程池的任务队列需要是阻塞队列。
我们之前说过Java中的线程池是生产者消费者模型线程的使用方——》生产可运行的任务Runnable task并且放到任务队列中供线程池中的线程进行消费任务的执行 4、当线程池的线程数等于线程核心数corePoolsize并且此时任务队列workQueue是满的状态。
这时如果来了新的Runnable Task线程池子就会创建新的线程来处理该任务。
直到线程数达到了maximumPoolSize——》就不会再继续创建新的线程来处理任务了。
这些新的线程在执行完了当前的任务后也不会被销毁。而是执行任务队列中的RunnableTask此时线程是忙碌状态非空闲当把任务队列中的任务执行完了后此时线程池中线程数应该是大于corePoolSize的那么接下来就会有一个判断逻辑——》判断线程是否需要被销毁当线程因为任务队列为空陷入阻塞进入空闲状态的时间大于keepAliveTime的时候该线程就会被销毁——》直到线程数等于corePoolSize 5、如果线程池中的线程数目达到了maximumSize并且此时任务队列也满了。
这种情况下还有新的任务过来那就直接采用拒绝的处理器进行处理。默认的处理器逻辑是抛出一个RejectedExecutionException异常
整个流程图如下 一点补充 使用线程池还要注意异常处理的问题例如通过 ThreadPoolExecutor 对象的 execute() 方法提交任务时如果任务在执行的过程中出现运行时异常会导致执行任务的线程终止不过最致命的是任务虽然异常了但是你却获取不到任何通知这会让你误以为任务都执行得很正常。虽然线程池提供了很多用于异常处理的方法但是最稳妥和简单的方案还是捕获所有异常并按需处理