文档章节

身为JAVA工作者必须了解的实战知识(十一)

 叶荷
发布于 2017/08/30 19:28
字数 1930
阅读 2
收藏 0
点赞 0
评论 0

并发测试大致分为两类:安全性测试(不发生任何错误的行为)和活跃性测试(某个良好的行为终究会发生)。

安全测试 - 通常采用测试不变性条件的形式,即判断某个类的行为是否与其他规范保持一致。

活跃性测试 - 包括进展测试和无进展测试两个方面。

性能测试与活跃性测试相关,主要包括:吞吐量、响应性、可伸缩性。

一、正确性测试

找出需要检查的不变条件和后延条件。

[java]view plaincopy

print?

importjava.util.concurrent.Semaphore;

publicclassBoundedBuffer {

privatefinalSemaphore availableItems, availableSpaces;

privatefinalE[] items;

privateintputPosition =0;

privateinttakePosition =0;

@SuppressWarnings("unchecked")

publicBoundedBuffer(intcapacity) {

availableItems =newSemaphore(0);

availableSpaces =newSemaphore(capacity);

items = (E[])newObject[capacity];

}

publicbooleanisEmpty() {

returnavailableItems.availablePermits() ==0;

}

publicbooleanisFull() {

returnavailableSpaces.availablePermits() ==0;

}

publicvoidput(E x)throwsInterruptedException {

availableSpaces.acquire();

doInsert(x);

availableItems.release();

}

publicE take()throwsInterruptedException {

availableItems.acquire();

E item = doExtract();

availableSpaces.release();

returnitem;

}

privatesynchronizedvoiddoInsert(E x) {

inti = putPosition;

items[i] = x;

putPosition = (++i == items.length)?0: i;

}

privatesynchronizedE doExtract() {

inti = takePosition;

E x = items[i];

items[i] =null;

takePosition = (++i == items.length)?0: i;

returnx;

}

}

1 基本的单元测试

[java]view plaincopy

print?

importstaticorg.junit.Assert.*;

importorg.junit.Test;

publicclassBoundedBufferTests {

@Test

publicvoidtestIsEmptyWhenConstructed() {

BoundedBuffer bb =newBoundedBuffer(10);

assertTrue(bb.isEmpty());

assertFalse(bb.isFull());

}

@Test

publicvoidtestIsFullAfterPuts()throwsInterruptedException {

BoundedBuffer bb =newBoundedBuffer(10);

for(inti =0; i <10; i++) {

bb.put(i);

}

assertTrue(bb.isFull());

assertTrue(bb.isEmpty());

}

}

2 对阻塞操作的测试

take方法是否阻塞、中断处理。从空缓存中获取一个元素。

[java]view plaincopy

print?

@Test

publicvoidtestTakeBlocksWhenEmpty(){

finalBoundedBuffer bb =newBoundedBuffer(10);

Thread taker =newThread(){

@Override

publicvoidrun() {

try{

intunused =  bb.take();

fail();//如果执行到这里,那么表示出现了一个错误

}catch(InterruptedException e) { }

}

};

try{

taker.start();

Thread.sleep(LOCKUP_DETECT_TIMEOUT);

taker.interrupt();

taker.join(LOCKUP_DETECT_TIMEOUT);

assertFalse(taker.isAlive());

}catch(InterruptedException e) {

fail();

}

}

创建一个“获取”线程,该线程将尝试从空缓存中获取一个元素。

如果take方法成功,那么表示测试失败。

执行测试的线程启动“获取”线程,等待一段时间,然后中断该线程。

如果“获取”线程正确地在take方法中阻塞,那么将抛出InterruptedException,而捕获到这个异常的catch块将把这个异常视为测试成功,并让线程退出。

然后,主测试线程会尝试与“获取”线程合并,通过调用Thread.isAlive来验证join方法是否成功返回,如果“获取”线程可以响应中断,那么join能很快地完成。

使用Thread.getState来验证线程能否在一个条件等待上阻塞,但这种方法并不可靠。被阻塞线程并不需要进入WAITING或者TIMED_WAITING等状态,因此JVM可以选择通过自旋等待来实现阻塞。

3 安全性测试

在构建对并发类的安全性测试中,需要解决地关键性问题在于,要找出那些容易检查的属性,这些属性在发生错误的情况下极有可能失败,同时又不会使得错误检查代码人为地限制并发性。理想情况是,在测试属性中不需要任何同步机制。

[java]view plaincopy

print?

importjava.util.concurrent.CyclicBarrier;

importjava.util.concurrent.ExecutorService;

importjava.util.concurrent.Executors;

importjava.util.concurrent.atomic.AtomicInteger;

importjunit.framework.TestCase;

publicclassPutTakeTestextendsTestCase {

privatestaticfinalExecutorService pool = Executors.newCachedThreadPool();

privatefinalAtomicInteger putSum =newAtomicInteger(0);

privatefinalAtomicInteger takeSum =newAtomicInteger(0);

privatefinalCyclicBarrier barrier;

privatefinalBoundedBuffer bb;

privatefinalintnTrials, nPairs;

publicstaticvoidmain(String[] args) {

newPutTakeTest(10,10,100000).test();// 示例参数

pool.shutdown();

}

staticintxorShift(inty) {

y ^= (y <<6);

y ^= (y >>>21);

y ^= (y <<7);

returny;

}

publicPutTakeTest(intcapacity,intnPairs,intnTrials) {

this.bb =newBoundedBuffer(capacity);

this.nTrials = nTrials;

this.nPairs = nPairs;

this.barrier =newCyclicBarrier(nPairs *2+1);

}

voidtest() {

try{

for(inti =0; i < nPairs; i++) {

pool.execute(newProducer());

pool.execute(newConsumer());

}

barrier.await();// 等待所有的线程就绪

barrier.await();// 等待所有的线程执行完成

assertEquals(putSum.get(), takeSum.get());

}catch(Exception e) {

thrownewRuntimeException(e);

}

}

classProducerimplementsRunnable {

@Override

publicvoidrun() {

try{

intseed = (this.hashCode() ^ (int) System.nanoTime());

intsum =0;

barrier.await();

for(inti = nTrials; i >0; --i) {

bb.put(seed);

sum += seed;

seed = xorShift(seed);

}

putSum.getAndAdd(sum);

barrier.await();

}catch(Exception e) {

thrownewRuntimeException(e);

}

}

}

classConsumerimplementsRunnable {

@Override

publicvoidrun() {

try{

barrier.await();

intsum =0;

for(inti = nTrials; i >0; --i) {

sum += bb.take();

}

takeSum.getAndAdd(sum);

barrier.await();

}catch(Exception e) {

thrownewRuntimeException(e);

}

}

}

}

4 资源管理的测试

对于任何持有或管理其他对象的对象,都应该在不需要这些对象时销毁对他们的引用。测试资源泄露的例子:

[java]view plaincopy

print?

classBig {

double[] data =newdouble[100000];

};

voidtestLeak()throwsInterruptedException{

BoundedBuffer bb =newBoundedBuffer(CAPACITY);

intheapSize1 =/* 生成堆的快照 */;

for(inti =0; i < CAPACITY; i++){

bb.put(newBig());

}

for(inti =0; i < CAPACITY; i++){

bb.take();

}

intheapSize2 =/* 生成堆的快照 */;

assertTrue(Math.abs(heapSize1 - heapSize2) < THRESHOLD);

}

5 使用回调

6 产生更多的交替操作

二、性能测试

性能测试的目标 - 根据经验值来调整各种不同的限值。例如:线程数量、缓存容量等。

1 在PutTakeTest中增加计时功能

基于栅栏的定时器

[java]view plaincopy

print?

this.timer =newBarrierTimer();

this.barrier =newCyclicBarrier(nPairs *2+1, timer);

publicclassBarrierTimerimplementsRunnable{

privatebooleanstarted ;

privatelongstartTime ;

privatelongendTime ;

@Override

publicsynchronizedvoidrun() {

longt = System.nanoTime();

if(!started ){

started =true;

startTime = t;

}else{

endTime = t;

}

}

publicsynchronizedvoidclear(){

started =false;

}

publicsynchronizedlonggetTime(){

returnendTime - startTime;

}

}

修改后的test方法中使用了基于栅栏的计时器

[java]view plaincopy

print?

voidtest(){

try{

timer.clear();

for(inti =0; i < nPairs; i++){

pool .execute(newProducer());

pool .execute(newConsumer());

}

barrier .await();

barrier .await();

longnsPerItem = timer.getTime() / ( nPairs * (long)nTrials );

System. out .println("Throughput: "+ nsPerItem +" ns/item");

assertEquals(putSum.get(), takeSum.get() )

}catch(Exception e) {

thrownewRuntimeException(e);

}

. 生产者消费者模式在不同参数组合下的吞吐率

. 有界缓存在不同线程数量下的伸缩性

. 如何选择缓存的大小

[java]view plaincopy

print?

publicstaticvoidmain(String[] args)throwsInterruptedException {

inttpt =100000;// 每个线程中的测试次数

for(intcap =1; cap <= tpt; cap *=10){

System. out .println("Capacity: "+ cap);

for(intpairs =1; pairs <=128; pairs *=2){

TimedPutTakeTest t =newTimedPutTakeTest(cap, pairs, tpt);

System. out .println("Pairs: "+ pairs +"\t");

t.test();

System. out .println("\t");

Thread. sleep(1000);

t.test();

System. out .println();

Thread. sleep(1000);

}

}

pool .shutdown();

}

查看吞吐量/线程数量的关系

2 多种算法的比较

3 响应性衡量

三、避免性能测试的陷阱

1 垃圾回收

2 动态编译

3 对代码路径的不真实采样

4 不真实的竞争程度

5 无用代码的消除

四、其他的测试方法

1 代码审查

2 静态分析工具

FindBugs、Lint

3 面向方面的测试技术

4 分析与监测工具

以上就是我推荐给Java开发者们的一面试经典知识。但是这些知识里面并没有太多Java全栈、Java晋阶、JAVA架构之类的题,不是我不推荐,而是希望大家更多的从基本功做起,打好基础,太多复杂的内容一会儿也说不明白。

好了同学们,我能介绍的也都全部介绍完给你们了,如果下获得更多JAVA教学资源,可以选择来我们这里共同交流,群:240448376,很多大神在这里切磋学习,不懂可以直接问,晚上还有大牛免费直播教学。

注:加群要求

1、具有一定工作经验的,面对目前流行的技术不知从何下手,需要突破技术瓶颈的可以加,有些应届生和实习生也可以加。

2、在公司待久了,过得很安逸,但跳槽时面试碰壁。需要在短时间内进修、跳槽拿高薪的可以加。

3、如果没有工作经验,但基础非常扎实,对java工作机制,常用设计思想,常用java开发框架掌握熟练的,可以加。

4、觉得自己很牛B,一般需求都能搞定。但是所学的知识点没有系统化,很难在技术领域继续突破的可以加。

5.阿里Java高级大牛直播讲解知识点,分享知识,多年工作经验的梳理和总结,带着大家全面、科学地建立自己的技术体系和技术认知!

PS:现在主要讲解的内容是(反射原理枚举原理与应用注解原理常用设计模式、正规表达式高级应用、JAVA操作Office原理详解JAVA图像处理技术,等多个知识点的详解和实战)

6.小号或者小白之类加群一律不给过,谢谢。

最后,每一位读到这里的网友,感谢你们能耐心地看完。觉得对你有帮助可以给个喜欢!希望在成为一名更优秀的Java程序员的道路上,我们可以一起学习、一起进步

© 著作权归作者所有

共有 人打赏支持
粉丝 0
博文 24
码字总数 41519
作品 0
Java 9 被无情抛弃,Java 8 直接升级到 Java 10!!

前几天写了一篇 Java 8 即将在 2019 年停止免费向企业提供更新的文章,企图迫使用户向更新一代的 Java 版本升级,但让人遗憾的是,小编今天收到了 Oracle Java 版本的升级推送,装完居然是 ...

Java技术栈 ⋅ 04/27 ⋅ 0

Java怎么学?2018最新Java学习路线,技术要求与项目推荐详解!

关注小编吧!! 回顾2017年,java发展的程度超乎了我们的想象,对技术的要求也越来越高,从原先的前端,后端的分布,到现在企业要求的全栈,对于个人能力的要求是逐步提高的,那我们现在究竟...

qq_41781067 ⋅ 05/23 ⋅ 0

书单丨5本Java后端技术书指引你快速进阶

一名Java开发工程师 不仅要对Java语言及特性有深层次的理解 而且需要掌握与Java相关的 框架、生态及后端开发知识 本文涉及多种后端开发需要掌握的技能 对于帮助提高开发能力非常有帮助 NO.1...

Java高级架构 ⋅ 05/30 ⋅ 0

Java程序员必读书单,家族又添新成员

点击关注异步图书,置顶公众号 每天与你分享IT好书 技术干货 职场知识 参与文末话题讨论,每日赠送异步图书。 ——异步小编 有些革命出其不意地吸引了全世界的眼球。Twitter、Linux操作系统和...

异步社区 ⋅ 05/09 ⋅ 0

Java 8 停止维护,Java 9 难产,IDEA 2018 发布,还有……

祝大家五一劳动节快乐,工作顺利! 又到了总结上个月干货的时候了,这个月我们带来了各种Java技术干货,各种送书抽奖福利,各种面试题分享,各种最新动态资讯等。 - 5.1重磅活动 区块链免费送...

Java技术栈 ⋅ 04/30 ⋅ 0

Java编程基础知识点和技术点归纳

Java是一种可以撰写跨平台应用软件的面向对象的程序设计语言。Java 技术具有卓越的通用性、高效性、平台移植性和安全性,广泛应用于PC、数据中心、游戏控制台、科学超级计算机、移动电话和互...

Java小辰 ⋅ 05/23 ⋅ 0

Java开发|Java新手应该怎么学习|2018年Java走势|

微信跳一跳你玩过吗,你知道怎么用Java开发出来吗?有时间可以研究一下!言归正传! 在2017回,java,发展程度超出我们的想象,对技术的要求也越来越高,从最初的前端、后端的布局,目前整个堆...

糖宝_d864 ⋅ 06/08 ⋅ 0

学会这几点,你会成为一名月薪过万的Java程序员

每一个稍微有点出息的人,都应该把行业里的前三名作为自己奋斗的目标和对手。你离成为冠军Java程序员还有多远,看完这篇你就知道了。 软件工程师的职业生涯里,知识有一个三年的半衰期。这意...

梦想远方_8e96 ⋅ 06/12 ⋅ 0

少走弯路,给Java 1~5 年程序员的建议

今天LZ是打算来点干货,因此咱们就不说一些学习方法和技巧了,直接来谈每个阶段要学习的内容甚至是一些书籍。这一部分的内容,同样适用于一些希望转行到Java的同学。 在大家看之前,LZ要先声...

重走Java ⋅ 05/29 ⋅ 0

Java开发学习之三版本简介 java编程

  Java编程语言,在更迭迅速的互联网领域多年屹立不倒,足以得见Java这门语言旺盛的生命力,因此,会有很多想要进入互联网领域的朋友,想要学Java来转行开发。但是,所谓“隔行如隔山”,j...

老男孩Linux培训 ⋅ 06/05 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Java集合类总结笔记

一、集合类的层次关系 主要容器集合类的特点: ArrayList 一种可以动态增长和缩减的索引序列 LinkedList 一种可以在任何位置进行高效地插入和删除的有序序列 ArrayDeque 一种用循环数组实现的...

edwardGe ⋅ 2分钟前 ⋅ 0

spring RMI远程调用

RMI https://www.cnblogs.com/wdh1995/p/6792407.html

BobwithB ⋅ 8分钟前 ⋅ 0

Jenkins实践2 之基本配置

1 插件管理 系统管理->插件管理 在可选插件中可以自主安装插件 2 管理用户 系统管理->管理用户->新建用户 3 安全配置 系统管理->全局安全配置 授权策略 选择安全矩阵 然后添加现有的用户,赋...

晨猫 ⋅ 8分钟前 ⋅ 0

c++智能指针

1、是一种泛型类,针对指针类型的泛型类,会保存指针 2、重载了符号 *和-> 对智能指针使用这两个符号,相当于对保存的泛型使用这两个符号 3、当智能指针引用计数为0时,会去释放指针指向的资...

国仔饼 ⋅ 9分钟前 ⋅ 0

Spring Boot错误处理机制

1)、SpringBoot默认的错误处理机制 默认效果: 1)、浏览器,返回一个默认的错误页面 浏览器发送请求的请求头: 2)、如果是其他客户端,默认响应一个json数据 原理: 可以参照ErrorMvcAut...

小致dad ⋅ 10分钟前 ⋅ 0

ftp连接不上的终极办法 SFTP

假如FTP由于各种原因就是连不上,那么用SFTP协议吧,使用登录服务器的账号密码。

sskill ⋅ 15分钟前 ⋅ 0

Unity 围绕旋转角度限制(Transform.RotateAround)

在 Unity 中可以利用 Transform.RotateAround 围绕指定物体进行旋转,但某些情况下可能需要对旋转角度进行控制。我是先计算出预设角度大小,然后判断是否在限定角度范围内是则进行旋转。 相关...

大轩 ⋅ 16分钟前 ⋅ 0

阿里沙箱环境支付宝测试demo

阿里支付宝支付和微信支付,包括:阿里沙箱环境支付宝测试demo,支付宝支付整合到spring+springmvc+mybatis环境和微信整合到如上环境,功能非常齐全,只需要修改对应的配置文件即可,帮助文档...

码代码的小司机 ⋅ 18分钟前 ⋅ 0

JDK1.6和JDK1.7中,Collections.sort的区别,

背景 最近,项目正在集成测试阶段,项目在服务器上运行了一段时间,点击表格的列进行排序的时候,有的列排序正常,有的列在排序的时候,在后台会抛出如下异常,查询到不到数据,而且在另外一...

tsmyk0715 ⋅ 35分钟前 ⋅ 0

C++ 中命名空间的 5 个常见用法

相信小伙伴们对C++已经非常熟悉,但是对命名空间经常使用到的地方还不是很明白,这篇文章就针对命名空间这一块做了一个叙述。 命名空间在1995年被引入到 c++ 标准中,通常是这样定义的: 命名...

柳猫 ⋅ 40分钟前 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部