第12章 并发程序的测试

大致分为两类:安全性测试和活跃性测试

12.1 正确性测试

找出需要检查的不变性条件和后验条件。接下来将构建一组测试用例来测试一个有界缓存。程序清单12-1给出了BoundedBuffer的实现,其中使用Semaphore来实现缓存的有界属性和阻塞行为。

BoundedBuffer实现了一个固定长度的队列,其中定义了可阻塞的put和take方法,并通过两个计数信号量进行控制。(实际情况中如果需要一个有界缓存,应该直接使用ArrayBlockingQueue或者LinkedBlockingDeque,而不是自己编写)。

12.1.1 基本的单元测试

BoundedBuffer的最基本单元测试类似与在串行上下文中执行的测试。首先创建一个有界缓存,然后调用它的各个方法,并验证它的后验条件和不变性条件。我们很快会想到一些不变性条件:新建立的缓存应该是空的,而不是满的。另一个略显复杂的安全测试是,将N个元素插入到容量为N的缓存中,然后测试缓存是否已经填满。

12.1.2 对阻塞操作的测试

在测试并发的基本属性时,需要引入多个线程。大多数测试框架并不能很好地支持并发性测试。在java.util.concurrent的一致性测试中,一定要将各种故障与特定的测试明确地关联起来。因此JSR 166专家组创建了一个基类,其中定义了一些可以在tearDown期间(主要实现测试完成后的垃圾回收等工作)传递和报告失败信息,并遵循一个约定:每个测试必须等待它锁创建的全部线程结束以后才能完成。

如果某方法需要在某些特定条件下阻塞,那么当测试这种行为时,只有当线程不再继续执行时,测试才是成功的。要测试一个方法的阻塞行为,类似于测试一个抛出异常的方法:如果这个方法可以正常返回,那么就意味着测试失败。在测试方法的阻塞行为时,将引入额外的复杂性:当方法被成功阻塞后,还必须使用方法接触阻塞。实现这个功能的一种简单方式就是使用中断——在一个单独的线程中启动一个阻塞操作。来个例子:

看了后面忘了前面。。。 现在补下之前的一些知识:

(1) 中断是通过调用Thread.interrupt()方法来做的. 这个方法通过修改了被调用线程的中断状态来告知那个线程, 说它被中断了. 对于非阻塞中的线程, 只是改变了中断状态, 即Thread.isInterrupted()将返回true; 对于可取消的阻塞状态中的线程, 比如等待在这些函数上的线程, Thread.sleep(), Object.wait(), Thread.join(), 这个线程收到中断信号后, 会抛出InterruptedException, 同时会把中断状态置回为false.

(2) t.join()方法阻塞调用此方法的线程(calling thread),直到线程t完成,此线程再继续;通常用于在main()主线程内,等待其它线程完成再结束main()主线程

如果take操作由于某种意料之外的原因停滞了,那么支持时限的join方法能够确保测试最终完成。用于验证线程能否在一个条件等待上阻塞的Thread.getState方法并不可靠(详见p208)

12.1.3 安全性测试

上面的几个测试程序无法发现由于数据竞争而引发的错误。要测试在生产者——消费者模式中使用的类,一种有效的方法就是检查被放入队列中和从队列中取出的各个元素。可以通过一个对顺序敏感的校验和计算函数里计算所有入列元素和出列元素的校验和,并进行比较。如果二者相等那么测试就死成功的。如果要将这种方法扩展到多生产者-多消费者模式的情况,就需要对元素入列/出列顺序不敏感的校验和函数,从而在测试程序运行完后,可以将多个校验和以不同的顺序组合起来。(这部分看得各种懵比)

当线程到达栅栏位置时调用栅栏的await方法,这个方法阻塞直到所有线程都达到栅栏的位置。如果所有线程都达到了栅栏的位置,那么栅栏将被打开,所有线程被释放,栅栏将被重置以便下次使用。

12.1.4 资源管理的测试(p212)

12.1.5 使用回调(p213) 

12.1.6 产生更多的交替操作(p214)

由于并发代码中的大多数错误都是一些低概率时间,因此在测试并发错误时需要反复地执行多次,所以有时候需要产生更多的交替操作。一种有用的方法是:在访问共享状态的操作中,使用Thread.yield将产生更多的上下文切换。

yield方法会使当前线程从执行状态(运行状态)变为可执行态(就绪状态)。cpu会从众多的可执行态里选择,也就是说,当前也就是刚刚的那个线程还是有可能会被再次执行到的,并不是说一定会执行其他线程而该线程在下一次中不会执行到了。

应该是面向切面的编程好伐,再次吐槽下这本书的翻译质量。

12.2 性能测试(p215)

12.2.1 在PutTakeTest中增加计时功能(p215)

记录整个运行过程的时间,然后除以操作数的量,从而得到每次操作的运行时间。使用一个栅栏动作来测量启动和结束时间:

老实说这部分我看到云里雾里的,不知道是不是翻译的原因(摔锅中...),二周目准备把这本书的英文版拿来看一遍。

12.2.2 多种算法的比较(p217)

12.2.3 响应性衡量(p219)

 

12.3 避免性能测试的陷阱(p220)

12.3.1 垃圾回收(p220)

垃圾回收的执行时序是无法预测的,因此在执行测试时,垃圾回收器可能在任何时刻运行。

12.3.2 动态编译(p220)

12.3.3 对代码路劲的不真实采样(p222)

12.3.4 不真实的竞争程度(p222)

12.3.5 无用代码的消除(p223)

12.4 其他的测试方法(p224)


总结:这章基本到后面就看不懂了...., 说了很多理论性的东西。其实我一直觉得理论这东西光说没用,要在实践的基础上理解才行。比较推崇先实践后理论的教学方式,而不是先从理论开始。这里再吐槽下这本书的翻译质量,坑啊。

《java并发编程实战》读书笔记9--并发程序的测试的更多相关文章

  1. Java多线程编程实战读书笔记(一)

    多线程的基础概念本人在学习多线程的时候发现一本书——java多线程编程实战指南.整理了一下书中的概念制作成了思维导图的形式.按照书中的章节整理,并添加一些个人的理解.

  2. Java并发编程实战 读书笔记(一)

    最近在看多线程经典书籍Java并发变成实战,很多概念有疑惑,虽然工作中很少用到多线程,但觉得还是自己太弱了.加油.记一些随笔.下面简单介绍一下线程. 一  线程与进程   进程与线程的解释   个人觉 ...

  3. Java并发编程实战 读书笔记(二)

    关于发布和逸出 并发编程实践中,this引用逃逸("this"escape)是指对象还没有构造完成,它的this引用就被发布出去了.这是危及到线程安全的,因为其他线程有可能通过这个 ...

  4. 《java并发编程实战》笔记

    <java并发编程实战>这本书配合并发编程网中的并发系列文章一起看,效果会好很多. 并发系列的文章链接为:  Java并发性和多线程介绍目录 建议: <java并发编程实战>第 ...

  5. Java并发编程实践读书笔记(5) 线程池的使用

    Executor与Task的耦合性 1,除非线程池很非常大,否则一个Task不要依赖同一个线程服务中的另外一个Task,因为这样容易造成死锁: 2,线程的执行是并行的,所以在设计Task的时候要考虑到 ...

  6. Java并发编程艺术读书笔记

    1.多线程在CPU切换过程中,由于需要保存线程之前状态和加载新线程状态,成为上下文切换,上下文切换会造成消耗系统内存.所以,可合理控制线程数量. 如何控制: (1)使用ps -ef|grep appn ...

  7. Java并发编程实践(读书笔记) 任务执行(未完)

    任务的定义 大多数并发程序都是围绕任务进行管理的.任务就是抽象和离散的工作单元.   任务的执行策略 1.顺序的执行任务 这种策略的特点是一般只有按顺序处理到来的任务.一次只能处理一个任务,后来其它任 ...

  8. Java并发编程实践读书笔记(2)多线程基础组件

    同步容器 同步容器是指那些对所有的操作都进行加锁(synchronize)的容器.比如Vector.HashTable和Collections.synchronizedXXX返回系列对象: 可以看到, ...

  9. Java并发编程实践读书笔记(1)线程安全性和对象的共享

    2.线程的安全性 2.1什么是线程安全 在多个线程访问的时候,程序还能"正确",那就是线程安全的. 无状态(可以理解为没有字段的类)的对象一定是线程安全的. 2.2 原子性 典型的 ...

随机推荐

  1. 常见的shell命令总结

    1.查看一个程序是否运行   ps –ef|grep tomcat 查看所有有关tomcat的进程 2.终止线程   kill -9 2222  3.查看文件,包含隐藏文件   ls -al 4.当前 ...

  2. 【BZOJ 3569】DZY Loves Chinese II 随机化+线性基

    用到一个结论——[先建树,再给每个非树边一个权值,每个树边的权值为覆盖他的非树边的权值的异或和,然后如果给出的边存在一个非空子集异或和为0则不连通,否则连通](必须保证每条边的出现和消失只能由自己产生 ...

  3. 【图论】tarjan的离线LCA算法

    百度百科 Definition&Solution 对于求树上\(u\)和\(v\)两点的LCA,使用在线倍增可以做到\(O(nlogn)\)的复杂度.在NOIP这种毒瘤卡常比赛中,为了代码的效 ...

  4. Django CRM系统

    本节内容 业务痛点分析 项目需求讨论 使用场景分析 表结构设计 业务痛点分析 我2013年刚加入老男孩教育的时候,学校就一间教室,2个招生老师,招了学生后,招生老师就在自己的excel表里记录一下,每 ...

  5. Mybatis中什么时候应该声明jdbcType

    转:http://blog.csdn.net/l799069596/article/details/52052777 疑问来自于,有时候Mapper.xml中 pid = #{pid,jdbcType ...

  6. stout代码分析之二:None类

    stout库中为了避免使用NULL带来的风险,统一用None表示空. None类的实现方式如下: struct None {}; 奇怪的是, Nothing类实现方式与None一模一样..让人怀疑作者 ...

  7. C#学习之泛型

    //主函数//主函数里面调用的类都在后面有具体描述 using System; using System.Collections.Generic; using System.Linq; using S ...

  8. ajax 请求数据的两种方法

    实现ajax 异步访问网络的方法有两个.第一个是原始的方法,第二个是利用jquery包的 原始的方法不用引入jquery包,只需在html中编写script 片段 这里我演示的是一个传递参数查询的例子 ...

  9. 【设计模式】 模式PK:抽象工厂模式VS建造者模式

    1.概述 抽象工厂模式实现对产品家族的创建,一个产品家族是这样的一系列产品:具有不同分类维度的产品组合,采用抽象工厂模式则是不需要关心构建过程,只关心什么产品由什么工厂生产即可.而建造者模式则是要求按 ...

  10. Value does not fall within the expected range 值不在预期的范围内

    用vs2012 打开web.config时,提示如下错误:“Value does not fall within the expected range”; 中文提示:“值不在预期的范围内” 解决方案: ...