第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. bzoj2330: [SCOI2011]糖果(差分约束)

    差分约束裸题,a==b的话分别建a>=b a<=b的边就行.倒序加边不然会TLE是什么鬼 #include<iostream> #include<cstring> ...

  2. Linux上读取文件

    Linux上读取文件的方法: #!/bin/bash # This is a script for test exec CONFIG_FILE=$ #该脚本传一个文件名为参数 FILE_NO= ech ...

  3. sql中按in中的ID进行排序输出

    builder.OrderBy("charindex(','+convert(varchar,ID)+',',',"+chufenOrder+"') ");

  4. bzoj 1113 [Poi2008]海报PLA 单调栈

    [Poi2008]海报PLA Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1304  Solved: 896[Submit][Status][Dis ...

  5. ACM2647拓扑排序逆运算

    2647题是对工人排序问题,不是从头到尾排序,而是从尾到头排序: 代码中用到vector和queue容器,权当练习. 用广搜进行拓扑排序的逆运算. #include<iostream> # ...

  6. 温习js中对象的继承

    温故而知新 XD 1. 关于原型和构造函数的几个知识要点: 使用new 操作符调用构造函数,会经历以下四个步骤: 1.1. 创建一个新对象: 1.2. 将构造函数的作用域赋给新对象(因此 this 就 ...

  7. 51Nod 1082 | 模拟

    Input示例 5 4 5 6 7 8 Output示例 30 55 91 91 155 模拟 #include "bits/stdc++.h" using namespace s ...

  8. 【hdu5381】维护区间内所有子区间的gcd之和-线段树

    题意:给定n个数,m个询问,每次询问一个区间内所有连续子区间的gcd的和.n,m<=10^5 题解: 这题和之前比赛的一题很像.我们从小到大枚举r,固定右端点枚举左端点,维护的区间最多只有log ...

  9. 【BZOJ】4430: [Nwerc2015]Guessing Camels赌骆驼

    [题意]给定三个长度为n的排列,求在三个排列中顺序相同的数对个数. [算法]逆序对 [题解]很容易联想到NOIP火柴排队,涉及顺序问题显然和逆序对息息相关. 一个数对如果在三个排列中顺序不同,一定是1 ...

  10. HDU 1180 诡异的楼梯 (广搜)

    题目链接 Problem Description Hogwarts正式开学以后,Harry发现在Hogwarts里,某些楼梯并不是静止不动的,相反,他们每隔一分钟就变动一次方向. 比如下面的例子里,一 ...