首页 / 互联网 / 正文
Java 线程Executor 框架详解与使用
xurongdadi 发表于:2019-9-3 15:12:46 复制链接 看图 发表新帖
阅读数:6291

下载APP可以快速和圈友联系

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
在HotSpot VM的线程模子中,Java线程被一对一映照为当地操纵系统线程。Java线程启动时会建立一个当地操纵系统线程;当该Java线程停止时,这个操纵系统线程也会被接管,在JVM中我们可以经过-Xss设备每个线程的巨细。操纵系统会调剂一切线程并将它们分派给可用的CPU。

在上层,java多线程法式凡是把利用分化为多少个使命,然后利用用户级的调剂器(Executor框架)将这些使命映照为牢固数目的线程;在底层,操纵系统内核将这些线程映照到硬件处置器上。这类两级调剂模子的表示图以下图所示

Java 线程Executor 框架详解与利用-1.jpeg


经过上图可以看出利用法式经过Executor控制上层调剂,操纵系统内核控制下层调剂。

注:oskernel操纵系统焦点包括操纵系统软件和利用,只是操纵系统最根基的功用,例如内存治理,进程治理,硬件驱动等

Executor结构

executor结构首要包括使命、使命的履行和异步成果的计较。

使命

包括被履利用命需要实现的接口:Runnable接口或Callable接口

使命的履行

包括使命履行机制的焦点接口Executor,以及继续自Executor的ExecutorService接口。Executor框架有两个关键类实现了ExecutorService接口(ThreadPoolExecutor和ScheduledThreadPoolExecutor)

异步计较的成果

包括接口Future和实现Future接口的FutureTask类

下面我们来看看executor类图

Java 线程Executor 框架详解与利用-2.jpeg


在Executor利用进程中,主线程首先要建立实现Runnable大概Callable接口的使命工具。工具类Executors可以把一个Runnable工具封装为一个Callable工具(Executors.callable(Runnable task)或Executors.callable(Runnable task,Object resule))。

假如履行ExecutorService.submit(…),ExecutorService将返回一个实现Future接口的工具(FutureTask)。由于FutureTask实现了Runnable,我们也可以建立FutureTask,然后间接交给ExecutorService履行。最初,主线程可以履行FutureTask.get()方式来期待使命履行完成。主线程也可以履行FutureTask.cancel(boolean mayInterruptIfRunning)来取消此使命的履行。

FixedThreadPool 初始化

Java 线程Executor 框架详解与利用-3.png


FixedThreadPool的corePoolSize和maximumPoolSize都被设备为建立FixedThreadPool时指定的参数nThreads。当线程池中的线程数大于corePoolSize时,keepAliveTime为过剩的余暇线程期待新使命的最长时候,跨越这个时候后过剩的线程将被停止。这里把keepAliveTime设备为0L,意味着过剩的余暇线程会被立即停止

运转进程

下面是FixedThreadPool运转进程表示图

Java 线程Executor 框架详解与利用-4.jpeg


    1、假如当前运转的线程数少于corePoolSize,则建立新线程来履利用命。

    2、在线程池完成预热以后(当前运转的线程数即是corePoolSize),将使命加入LinkedBlockingQueue。

    3、线程履行完1中的使命后,会在循环中频频从LinkedBlockingQueue获得使命来履行。

FixedThreadPool利用无界行列LinkedBlockingQueue作为线程池的工作行列(行列的容量为Integer.MAX_VALUE)。利用无界行列作为工作行列会对线程池带来以下影响

    1、当线程池中的线程数到达corePoolSize后,新使命将在无界行列中期待,是以线程池中的线程数不会跨越corePoolSize。

    2、由于1,利用无界行列时maximumPoolSize将是一个无效参数。

    3、由于1和2,利用无界行列时keepAliveTime将是一个无效参数。

    4、由于利用无界行列,运转中的FixedThreadPool(未履行方式shutdown()或shutdownNow())不会拒绝使命(不会挪用RejectedExecutionHandler.rejectedExecution方式)。

利用处景 FixedThreadPool适用于为了满足资本治理的需求,而需要限制当火线程数目的利用处景,它适用于负载比力重的办事器

SingleThreadExecutor 初始化

建立利用单个线程的SingleThread-Executor

Java 线程Executor 框架详解与利用-5.png


SingleThreadExecutor的corePoolSize和maximumPoolSize被设备为1。其他参数与FixedThreadPool不异。SingleThreadExecutor利用无界行列LinkedBlockingQueue作为线程池的工作行列(行列的容量为Integer.MAX_VALUE)。SingleThreadExecutor利用无界行列作为工作行列对线程池带来的影响与FixedThreadPool不异

运转进程

下图是SingleThreadExecutor的运转进程表示图

Java 线程Executor 框架详解与利用-6.jpeg


    1、假如当前运转的线程数少于corePoolSize(即线程池中无运转的线程),则建立一个新线程来履利用命。

    2、在线程池完成预热以后(当火线程池中有一个运转的线程),将使命加入LinkedBlockingQueue。

    3、线程履行完1中的使命后,会在一个无穷循环中频频从LinkedBlockingQueue获得使命来履行。

利用处景 SingleThreadExecutor适用于需要保证顺序地履行各个使命;而且在肆意时候点,不会有多个线程是活动的利用处景。

CachedThreadPool 初始化

Java 线程Executor 框架详解与利用-7.png


CachedThreadPool的corePoolSize被设备为0,即corePool为空;maximumPoolSize被设备为Integer.MAX_VALUE,即maximumPool是无界的。这里把keepAliveTime设备为60L,意味着CachedThreadPool中的余暇线程期待新使命的最长时候为60秒,余暇线程跨越60秒后将会被停止。

FixedThreadPool和SingleThreadExecutor利用无界行列LinkedBlockingQueue作为线程池的工作行列。CachedThreadPool利用没有容量的SynchronousQueue作为线程池的工作行列,但CachedThreadPool的maximumPool是无界的。这意味着,假如主线程提交使命的速度高于maximumPool中线程处置使命的速度时,CachedThreadPool会不竭建立新线程。极端情况下,CachedThreadPool会由于建立过量线程而耗尽CPU和内存资本。

运转进程

下图是CachedThreadPool的运转进程表示图

Java 线程Executor 框架详解与利用-8.jpeg


1、首先履行SynchronousQueue.offer(Runnable task)。假如当前maximumPool中不足暇线程正在履行SynchronousQueue.poll(keepAliveTime,TimeUnit.NANOSECONDS),那末主线程履行offer操纵与余暇线程履行的poll操纵配对成功,主线程把使命交给余暇线程履行,execute()方式履行完成;否则履行下面的步调2)。

2、当初始maximumPool为空,大概maximumPool中当前没不足暇线程时,将没有线程履行SynchronousQueue.poll

(keepAliveTime,TimeUnit.NANOSECONDS)。这类情况下,步调1)将失利。此时CachedThreadPool会建立一个新线程履利用命,execute()方式履行完成。

3、在步调2)中新建立的线程将使命履行完后,会履行SynchronousQueue.poll(keepAliveTime,TimeUnit.NANOSECONDS)。这个poll操纵会让余暇线程最多在SynchronousQueue中期待60秒钟。假如60秒钟内主线程提交了一个新使命(主线程履行步调1)),那末这个余暇线程将履行主线程提交的新使命;否则,这个余暇线程将停止。由于余暇60秒的余暇线程会被停止,是以长时候连结余暇的CachedThreadPool不会利用任何资本。

前面提到过,SynchronousQueue是一个没有容量的阻塞行列。每个插入操纵必须期待另一个线程的对应移除操纵,反之亦然。CachedThreadPool利用SynchronousQueue,把主线程提交的使命传递给余暇线程履行。CachedThreadPool中使命传递的表示图以下图所示:

Java 线程Executor 框架详解与利用-9.jpeg


利用处景

看名字我们可以晓得cached缓存,CachedThreadPool可以建立一个可按照需要建立新线程的线程池,可是在之前机关的线程可用时将重用它们,对于履行很多短期异步使命的法式而言,这些线程池凡是可进步法式性能。挪用 execute 将重用之前机关的线程(假如线程可用)。假如现有线程没有可用的,则建立一个新线程并增加到池中。

CachedThreadPool是巨细无界的线程池,适用于履行很多的短期异步使命的小法式,大概是负载较轻的办事器。

ScheduledThreadPoolExecutor

ScheduledThreadPoolExecutor继续自ThreadPoolExecutor。它首要用来在给定的提早以后运转使命,大概定期履利用命。ScheduledThreadPoolExecutor的功用与Timer类似,但ScheduledThreadPoolExecutor功用更强大、更灵活。Timer对应的是单个背景线程,而ScheduledThreadPoolExecutor可以在机关函数中指定多个对应的背景线程数

初始化

ScheduledThreadPoolExecutor凡是利用工场类Executors来建立。Executors可以建立2品种型的ScheduledThreadPoolExecutor,以下。

ScheduledThreadPoolExecutor:包括多少个线程的ScheduledThreadPoolExecutor。

SingleThreadScheduledExecutor:只包括一个线程的ScheduledThreadPoolExecutor。

下面别离先容这两种ScheduledThreadPoolExecutor。

Java 线程Executor 框架详解与利用-10.png


间接挪用父类ThreadPoolExecutor机关方式停止初始化。ScheduledThreadPoolExecutor适用于需要多个背景线程履行周期使命,同时为了满足资本治理的需求而需要限制背景线程的数目的利用处景。

下面看看若何建立SingleThreadScheduledExecutor

Java 线程Executor 框架详解与利用-11.png


运转进程

DelayQueue是一个无界行列,所以ThreadPoolExecutor的maximumPoolSize在ScheduledThreadPoolExecutor中没有什么意义(设备maximumPoolSize的巨细没有什么结果)。ScheduledThreadPoolExecutor的履行首要分为两大部分。

1、当挪用ScheduledThreadPoolExecutor的scheduleAtFixedRate()方式大概scheduleWithFixedDelay()方式时,会向ScheduledThreadPoolExecutor的DelayQueue增加一个实现了RunnableScheduledFutur接口的ScheduledFutureTask。

2、线程池中的线程从DelayQueue中获得ScheduledFutureTask,然后履利用命。

下面看看ScheduedThreadPoolExecutor运转进程表示图

Java 线程Executor 框架详解与利用-12.jpeg


ScheduledThreadPoolExecutor为了实现周期性的履利用命,对ThreadPoolExecutor做了以下

的点窜。

    1、利用DelayQueue作为使命行列。

    2、获得使命的方式分歧(后文会说明)。

    3、履行周期使命后,增加了额外的处置(后文会说明)。

实现进程分析 ScheduledThreadPoolExecutor会把待调剂的使命(ScheduledFutureTask)放到一个DelayQueue中。ScheduledFutureTask首要包括3个成员变量,以下。

    1、long time,暗示这个使命将要被履行的具体时候。

    2、long sequenceNumber,暗示这个使命被增加到ScheduledThreadPoolExecutor中的序号。

    3、long period,暗示使命履行的间隔周期。

DelayQueue封装了一个PriorityQueue,这个PriorityQueue会对行列中的ScheduledFutureTask停止排序。排序时,time小的排在前面(时候早的使命将被先履行)。假如两个ScheduledFutureTask的time不异,就比力sequenceNumber,sequenceNumber小的排在前面(也就是说,假如两个使命的履行时候不异,那末先提交的使命将被先履行)。首先,让我们看看ScheduledThreadPoolExecutor中的线程履行周期使命的进程。以下图所示

Java 线程Executor 框架详解与利用-13.jpeg


    1、线程1从DelayQueue中获得已到期的ScheduledFutureTask(DelayQueue.take())。到期使命是指ScheduledFutureTask的time大于即是当前时候。

    2、线程1履行这个ScheduledFutureTask。

    3、线程1点窜ScheduledFutureTask的time变量为下次将要被履行的时候。

    4、线程1把这个点窜time以后的ScheduledFutureTask放回DelayQueue中(DelayQueue.add())。

下面我们看看DelayQueue.take()的源码是若何实现的

Java 线程Executor 框架详解与利用-14.png


下面我们对上面的代码用流程图展现出来

Java 线程Executor 框架详解与利用-15.jpeg


1、获得Lock。

2、获得周期使命。

    a、假如PriorityQueue为空,当火线程到Condition中期待;否则履行下面的2.2。

    b、假如PriorityQueue的头元素的time时候比当前时候大,到Condition中期待到time时候;否则履行下面的2.3。

    c、获得PriorityQueue的头元素(2.3.1);假如PriorityQueue不为空,则叫醒在Condition中期待的一切线程(2.3.2)。

3、开释Lock。

ScheduledThreadPoolExecutor在一个循环中履行步调2,直到线程从PriorityQueue获得到一个元素以后(履行2.3.1以后),才会退出无穷循环(竣事步调2)。

下面我来看看DelayQueue.add()源码实现

Java 线程Executor 框架详解与利用-16.png


下面我们对上面的代码用流程图展现出来

Java 线程Executor 框架详解与利用-17.jpeg


1、获得Lock。

2、增加使命。

    a、向PriorityQueue增加使命。

    b、假如在上面2.1中增加的使命是PriorityQueue的头元素,叫醒在Condition中期待的一切线程。

3、开释Lock。

利用处景

SingleThreadScheduledExecutor适用于需要单个背景线程履行周期使命,同时需要保证顺序地履行各个使命的利用处景。


上一篇:Java版坦克大战游戏源码
下一篇:给我两分钟,让你秒懂Java是什么
温馨提示:
下载好向圈客户端可以随时随地交流学习经验,也可以和圈友发起聊天成为好友
好向圈www.kuaixunai.com是一个专业经验分享交流平台,请提供优质的经验内容分享,拒绝任何广告内容出现,低质量广告内容硬广包含手机号码,微信,QQ或者二维码,网址等形式存在可能会审核不通过 要想被各大搜索引擎尽快收录请做好内容原创工作,才会有更好的推广效果。
返回列表
使用道具 举报
条评论
您需要登录后才可以回帖 登录 | 立即注册
相关推荐
广告合作以及侵权投诉客服QQ:1623331347 江苏好向圈信息科技有限公司 网站地图1 网站地图2