多平台统一管理软件接口,如何实现多平台统一管理软件接口
335
2023-04-21
本文目录一览:
大家好,我是冰河~~
本文有点长,但是满满的干货,以实际案例的形式分析了两种异步模型,并从源码角度深度解析Future接口和FutureTask类,希望大家踏下心来,打开你的IDE,跟着文章看源码,相信你一定收获不小!
在Java的并发编程中,大体上会分为两种异步编程模型,一类是直接以异步的形式来并行运行其他的任务,不需要返回任务的结果数据。一类是以异步的形式运行其他任务,需要返回结果。
1.无返回结果的异步模型
无返回结果的异步任务,可以直接将任务丢进线程或线程池中运行,此时,无法直接获得任务的执行结果数据,一种方式是可以使用回调方法来获取任务的运行结果。
具体的方案是:定义一个回调接口,并在接口中定义接收任务结果数据的方法,具体逻辑在回调接口的实现类中完成。将回调接口与任务参数一同放进线程或线程池中运行,任务运行后调用接口方法,执行回调接口实现类中的逻辑来处理结果数据。这里,给出一个简单的示例供参考。
便于接口的通用型,这里为回调接口定义了泛型。
回调接口的实现类主要用来对任务的返回结果进行相应的业务处理,这里,为了方便演示,只是将结果数据返回。大家需要根据具体的业务场景来做相应的分析和处理。
任务的执行类是具体执行任务的类,实现Runnable接口,在此类中定义一个回调接口类型的成员变量和一个String类型的任务参数(模拟任务的参数),并在构造方法中注入回调接口和任务参数。在run方法中执行任务,任务完成后将任务的结果数据封装成TaskResult对象,调用回调接口的方法将TaskResult对象传递到回调方法中。
到这里,整个大的框架算是完成了,接下来,就是测试看能否获取到异步任务的结果了。
在测试类中,使用Thread类创建一个新的线程,并启动线程运行任务。运行程序最终的接口数据如下所示。
大家可以细细品味下这种获取异步结果的方式。这里,只是简单的使用了Thread类来创建并启动线程,也可以使用线程池的方式实现。大家可自行实现以线程池的方式通过回调接口获取异步结果。
2.有返回结果的异步模型
尽管使用回调接口能够获取异步任务的结果,但是这种方式使用起来略显复杂。在JDK中提供了可以直接返回异步结果的处理方案。最常用的就是使用Future接口或者其实现类FutureTask来接收任务的返回结果。
使用Future接口往往配合线程池来获取异步执行结果,如下所示。
运行结果如下所示。
FutureTask类既可以结合Thread类使用也可以结合线程池使用,接下来,就看下这两种使用方式。
结合Thread类的使用示例如下所示。
运行结果如下所示。
结合线程池的使用示例如下。
运行结果如下所示。
可以看到使用Future接口或者FutureTask类来获取异步结果比使用回调接口获取异步结果简单多了。注意:实现异步的方式很多,这里只是用多线程举例。
接下来,就深入分析下Future接口。
1.Future接口
Future是JDK1.5新增的异步编程接口,其源代码如下所示。
可以看到,在Future接口中,总共定义了5个抽象方法。接下来,就分别介绍下这5个方法的含义。
取消任务的执行,接收一个boolean类型的参数,成功取消任务,则返回true,否则返回false。当任务已经完成,已经结束或者因其他原因不能取消时,方法会返回false,表示任务取消失败。当任务未启动调用了此方法,并且结果返回true(取消成功),则当前任务不再运行。如果任务已经启动,会根据当前传递的boolean类型的参数来决定是否中断当前运行的线程来取消当前运行的任务。
判断任务在完成之前是否被取消,如果在任务完成之前被取消,则返回true;否则,返回false。
这里需要注意一个细节:只有任务未启动,或者在完成之前被取消,才会返回true,表示任务已经被成功取消。其他情况都会返回false。
判断任务是否已经完成,如果任务正常结束、抛出异常退出、被取消,都会返回true,表示任务已经完成。
当任务完成时,直接返回任务的结果数据;当任务未完成时,等待任务完成并返回任务的结果数据。
当任务完成时,直接返回任务的结果数据;当任务未完成时,等待任务完成,并设置了超时等待时间。在超时时间内任务完成,则返回结果;否则,抛出TimeoutException异常。
2.RunnableFuture接口
Future接口有一个重要的子接口,那就是RunnableFuture接口,RunnableFuture接口不但继承了Future接口,而且继承了java.lang.Runnable接口,其源代码如下所示。
这里,问一下,RunnableFuture接口中有几个抽象方法?想好了再说!哈哈哈。。。
这个接口比较简单run()方法就是运行任务时调用的方法。
3.FutureTask类
FutureTask类是RunnableFuture接口的一个非常重要的实现类,它实现了RunnableFuture接口、Future接口和Runnable接口的所有方法。FutureTask类的源代码比较多,这个就不粘贴了,大家自行到java.util.concurrent下查看。
(1)FutureTask类中的变量与常量
在FutureTask类中首先定义了一个状态变量state,这个变量使用了volatile关键字修饰,这里,大家只需要知道volatile关键字通过内存屏障和禁止重排序优化来实现线程安全,后续会单独深度分析volatile关键字是如何保证线程安全的。紧接着,定义了几个任务运行时的状态常量,如下所示。
其中,代码注释中给出了几个可能的状态变更流程,如下所示。
接下来,定义了其他几个成员变量,如下所示。
又看到我们所熟悉的Callable接口了,Callable接口那肯定就是用来调用call()方法执行具体任务了。
看一下WaitNode类的定义,如下所示。
可以看到,WaitNode类是FutureTask类的静态内部类,类中定义了一个Thread成员变量和指向下一个WaitNode节点的引用。其中通过构造方法将thread变量设置为当前线程。
(2)构造方法
接下来,是FutureTask的两个构造方法,比较简单,如下所示。
(3)是否取消与完成方法
继续向下看源码,看到一个任务是否取消的方法,和一个任务是否完成的方法,如下所示。
这两方法中,都是通过判断任务的状态来判定任务是否已取消和已完成的。为啥会这样判断呢?再次查看FutureTask类中定义的状态常量发现,其常量的定义是有规律的,并不是随意定义的。其中,大于或者等于CANCELLED的常量为CANCELLED、INTERRUPTING和INTERRUPTED,这三个状态均可以表示线程已经被取消。当状态不等于NEW时,可以表示任务已经完成。
通过这里,大家可以学到一点:以后在编码过程中,要按照规律来定义自己使用的状态,尤其是涉及到业务中有频繁的状态变更的操作,有规律的状态可使业务处理变得事半功倍,这也是通过看别人的源码设计能够学到的,这里,建议大家还是多看别人写的优秀的开源框架的源码。
(4)取消方法
我们继续向下看源码,接下来,看到的是cancel(boolean)方法,如下所示。
接下来,拆解cancel(boolean)方法。在cancel(boolean)方法中,首先判断任务的状态和CAS的操作结果,如果任务的状态不等于NEW或者CAS的操作返回false,则直接返回false,表示任务取消失败。如下所示。
接下来,在try代码块中,首先判断是否可以中断当前任务所在的线程来取消任务的运行。如果可以中断当前任务所在的线程,则以一个Thread临时变量来指向运行任务的线程,当指向的变量不为空时,调用线程对象的interrupt()方法来中断线程的运行,最后将线程标记为被中断的状态。如下所示。
这里,发现变更任务状态使用的是UNSAFE.putOrderedInt()方法,这个方法是个什么鬼呢?点进去看一下,如下所示。
可以看到,又是一个本地方法,嘿嘿,这里先不管它,后续文章会详解这些方法的作用。
接下来,cancel(boolean)方法会进入finally代码块,如下所示。
可以看到在finallly代码块中调用了finishCompletion()方法,顾名思义,finishCompletion()方法表示结束任务的运行,接下来看看它是如何实现的。点到finishCompletion()方法中看一下,如下所示。
在finishCompletion()方法中,首先定义一个for循环,循环终止因子为waiters为null,在循环中,判断CAS操作是否成功,如果成功进行if条件中的逻辑。首先,定义一个for自旋循环,在自旋循环体中,唤醒WaitNode堆栈中的线程,使其运行完成。当WaitNode堆栈中的线程运行完成后,通过break退出外层for循环。接下来调用done()方法。done()方法又是个什么鬼呢?点进去看一下,如下所示。
可以看到,done()方法是一个空的方法体,交由子类来实现具体的业务逻辑。
当我们的具体业务中,需要在取消任务时,执行一些额外的业务逻辑,可以在子类中覆写done()方法的实现。
(5)get()方法
继续向下看FutureTask类的代码,FutureTask类中实现了两个get()方法,如下所示。
没参数的get()方法为当任务未运行完成时,会阻塞,直到返回任务结果。有参数的get()方法为当任务未运行完成,并且等待时间超出了超时时间,会TimeoutException异常。
两个get()方法的主要逻辑差不多,一个没有超时设置,一个有超时设置,这里说一下主要逻辑。判断任务的当前状态是否小于或者等于COMPLETING,也就是说,任务是NEW状态或者COMPLETING,调用awaitDone()方法,看下awaitDone()方法的实现,如下所示。
接下来,拆解awaitDone()方法。在awaitDone()方法中,最重要的就是for自旋循环,在循环中首先判断当前线程是否被中断,如果已经被中断,则调用removeWaiter()将当前线程从堆栈中移除,并且抛出InterruptedException异常,如下所示。
接下来,判断任务的当前状态是否完成,如果完成,并且堆栈句柄不为空,则将堆栈中的当前线程设置为空,返回当前任务的状态,如下所示。
当任务的状态为COMPLETING时,使当前线程让出CPU资源,如下所示。
如果堆栈为空,则创建堆栈对象,如下所示。
如果queued变量为false,通过CAS操作为queued赋值,如果awaitDone()方法传递的timed参数为true,则计算超时时间,当时间已超时,则在堆栈中移除当前线程并返回任务状态,如下所示。如果未超时,则重置超时时间,如下所示。
如果不满足上述的所有条件,则将当前线程设置为等待状态,如下所示。
接下来,回到get()方法中,当awaitDone()方法返回结果,或者任务的状态不满足条件时,都会调用report()方法,并将当前任务的状态传递到report()方法中,并返回结果,如下所示。
看来,这里还要看下report()方法啊,点进去看下report()方法的实现,如下所示。
可以看到,report()方法的实现比较简单,首先,将outcome数据赋值给x变量,接下来,主要是判断接收到的任务状态,如果状态为NORMAL,则将x强转为泛型类型返回;当任务的状态大于或者等于CANCELLED,也就是任务已经取消,则抛出CancellationException异常,其他情况则抛出ExecutionException异常。
至此,get()方法分析完成。注意:一定要理解get()方法的实现,因为get()方法是我们使用Future接口和FutureTask类时,使用的比较频繁的一个方法。
(6)set()方法与setException()方法
继续看FutureTask类的代码,接下来看到的是set()方法与setException()方法,如下所示。
通过源码可以看出,set()方法与setException()方法整体逻辑几乎一样,只是在设置任务状态时一个将状态设置为NORMAL,一个将状态设置为EXCEPTIONAL。
至于finishCompletion()方法,前面已经分析过。
(7)run()方法与runAndReset()方法
接下来,就是run()方法了,run()方法的源代码如下所示。
可以这么说,只要使用了Future和FutureTask,就必然会调用run()方法来运行任务,掌握run()方法的流程是非常有必要的。在run()方法中,如果当前状态不是NEW,或者CAS操作返回的结果为false,则直接返回,不再执行后续逻辑,如下所示。
接下来,在try代码块中,将成员变量callable赋值给一个临时变量c,判断临时变量不等于null,并且任务状态为NEW,则调用Callable接口的call()方法,并接收结果数据。并将ran变量设置为true。当程序抛出异常时,将接收结果的变量设置为null,ran变量设置为false,并且调用setException()方法将任务的状态设置为EXCEPTIONA。接下来,如果ran变量为true,则调用set()方法,如下所示。
接下来,程序会进入finally代码块中,如下所示。
这里,将runner设置为null,如果任务的当前状态大于或者等于INTERRUPTING,也就是线程被中断了。则调用handlePossibleCancellationInterrupt()方法,接下来,看下handlePossibleCancellationInterrupt()方法的实现。
可以看到,handlePossibleCancellationInterrupt()方法的实现比较简单,当任务的状态为INTERRUPTING时,使用while()循环,条件为当前任务状态为INTERRUPTING,将当前线程占用的CPU资源释放,也就是说,当任务运行完成后,释放线程所占用的资源。
runAndReset()方法的逻辑与run()差不多,只是runAndReset()方法会在finally代码块中将任务状态重置为NEW。runAndReset()方法的源代码如下所示,就不重复说明了。
(8)removeWaiter()方法
removeWaiter()方法中主要是使用自旋循环的方式来移除WaitNode中的线程,比较简单,如下所示。
最后,在FutureTask类的最后,有如下代码。
关于这些代码的作用,会在后续深度解析CAS文章中详细说明,这里就不再探讨。
至此,关于Future接口和FutureTask类的源码就分析完了。
好了,今天就到这儿吧,我是冰河,我们下期见~~
接口测试最近几年被炒的火热了,越来越多的测试同行意识到接口测试的重要性。接口测试为什么会如此重要呢? 主要是平常的功能点点点,大家水平都一样,是个人都能点,面试时候如果问你平常在公司怎么测试的,你除了说点点点,还能说什么呢,无非就是这个项目点完了点那个项目, 这就是为什么各行各业的只要手指能点得动的人都来转行软件测试了。面试的时候面试官希望你除了点点点,还能更深入一点的思考页面上看不到的功能,也就是接口测试了。接口是看不见的,但是可以访问!
DNS是域名系统(Domain Name System) ,DNS是用来做域名解析的,它会在你上网输入网址后,把它转换成IP,然后去访问对方服务器;没有它,你想上百度就要记住百度的IP,但有了DNS的处理,你只需要记住对应网站的域名,即网址就可以了。
HTTP协议:超文本传输协议,是基于TCP的协议,默认为80端口。它的作用是用来规定客户端和服务器的数据传输格式。是一种用于请求与响应模式的、无状态、无连接 的应用层协议。 由于HTTP协议是一种请求-响应模式,所以一般需要关注HTTP请求和HTTP响应。
使用fiddler工具抓取HTTPS, 具体操作请查看文末领取教程
1xx -- 信息提示(表示临时的响应。客户端在收到常规响应之前,准备接收一个或多个1xx响应)
2xx -- 成功(表明服务器成功地接受了客户端请求)
3xx -- 重定向(客户端浏览器必须采取更多操作来实现请求。例如,浏览器可能不得不请求服务器上的不同的页面,或通过代理服务器重复该请求)
4xx -- 客户端错误(发送错误,客户端有问题。例如,客户端请求不存在的页面,客户端未提供有效的身份证验证信息)
5xx -- 服务器错误(服务器由于遇到错误而不能完成该请求)
常见的返回码有:
200 OK - [GET]:服务器成功返回用户请求的数据
201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功
202 Aceepted - [*]:表示一个请求已经进入后台排队(异步任务)
204 NO CONTENT - [DELETE]:用户删除数据成功
400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作
401 Unauthorized -[*] :表示用户没有权限(令牌、用户名、密码错误)
403 Forbidden -[*] :表示用户得到授权(与401错误相对),但是访问被禁止
404 NOT FOUND -[*]:用户发出的请求针对得到是不存在的记录,服务器没有进行操作,该操作是幂等的
406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。
410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。
422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。
500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。
HTTP协议常用的请求方式有如下几种:
HTTP协议传输的数据都是未加密的,也就是明文的,因此使用HTTP协议传输隐私信息非常不安全,为了保证这些隐私数据能加密传输,于是网景公司设计了SSL(Secure Sockets Layer)协议用于对HTTP协议传输的数据进行加密,从而就诞生了HTTPS。简单来说,HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,要比http协议安全。
HTTPS和HTTP的区别主要如下:
1、https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。
2、http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
3、http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
4、http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
POST和GET都是向服务器提交数据,并且都会从服务器获取数据。
区别:
(1)传送方式:get通过地址栏传输,post通过报文传输
(2)传送长度:get参数有长度限制(受限于url长度),而post无限制
(3)GET产生一个TCP数据包(对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200返回数据),POST产生两个TCP数据包(对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok返回数据)
(4)get请求参数会被完整保留在浏览历史记录里,而post中的参数不会被保留
(5)在做数据查询时,建议用GET方式;而在做数据添加、修改或删除时,建议用post方式
请求报文: 一个HTTP请求报文由请求行(Request Line)、请求头(Header)、空行(Blank Line)和请求体(Body)4个部分组成。
响应报文: HTTP响应报文和请求报文的结构差不多,由状态行、响应头、空行、响应体4个部分组成。
是指协议对于事务处理没有记忆能力,服务器不知道客户端是什么状态。即我们给服务器发送 HTTP 请求之后,服务器根据请求,会给我们发送数据过来,但是,发送完,不会记录任何信息。
解决方案:通过cookie和session来保持状态。
请求body;请求url+请求body:
Content-type:
application/x-www-form-urlencoded: 表单提交--键值对, form
multipart/form-data:文件上传---文件 ,MIME
application/json,text/xml:
http协议目前有4个版本(0.9,1.0,1.1,2.0),其中1.0、1.1版本在互联网上被广泛使用,2.0版本目前应用很少,是下一代的http协议。
1.存储位置不同:Cookie 是将用户数据通过加密的方式保存在客户端,大多数情况 Cookie 存储在浏览器;Session 是用于控制客户端和服务端的连接,Session 存储在服务器;
2.存储容量不同:单个 Cookie 保存的数据不得超过 4kb,一个站点最多 20 个 Cookie,Session 一般情况下没有上限,不过建议不要存放太多东西,否则影响性能;
3.存取方式不同:Cookie 只能用 ASCII 字符串,通过编码方式获取 Unicode 字符或者二进制数据,不好存储复杂的信息,而 Session 能存储任何类型的数据;
4.隐私策略/安全性不同:Cookie 放在客户端,可以进行 Cookie 欺骗,所以不安全,Session 放在服务端,更加安全;
5.有效期不同:Cookie 可以设置属性达到长期有效,Session 依赖于 JSESSIONID 的 Cookie,Cookie JSESSIONID 的过期时间默认为-1,只需要关闭窗口 Session 就会失效,就算不依赖 Cookie,用 UrL 重写也不能完成,如果 Session 超时时间过长,容易导致内存溢出;
6.服务器压力不同:Cookie 保存在本地,不存在服务端压力,Session 保存在服务端,每个用户产生一个 Session,当访问增多,会比较占用服务器的性能,如果主要考虑到减轻服务器性能方面,应当使用 Cookie;
7.浏览器支持不同:如果浏览器禁用 Cookie,那么 Cookie 直接失效,Session 比较好点,可以用 URL 重写;
8.Cookie 和 Session 应用的场景:Cookie 一般用于记住用户的登录状态,如记录用户的习惯,购物车;而 Session 用于登录验证。
https在应用层。
会话层为7层协议的第五层,为表示层提供建立、维护和结束会话连接的功能,并提供会话管理服务。
在浏览器中输入URL并回车后,主要发生以下步骤:
解析URL,获取要访问的域名
DNS域名解析,根据访问的域名获得目标服务器的IP地址
浏览器与服务端三次握手建立TCP连接
连接建立成功之后就可以发送HTTP请求报文以及服务器返回HTTP响应报文
断开TCP链接
浏览器解析响应报文,渲染页面
关于异步接口测试和异步接口实现的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。 异步接口测试的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于异步接口实现、异步接口测试的信息别忘了在本站进行查找喔。版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~