并发编程11-测试并发程序

简介: <div class="markdown_views"><p>测试的两个方面: <br>- 安全性 并发不会造成状态错误。 <br>- 活跃度 主要是性能测试 <br> - 吞吐量 段时间定资源内可以处理的任务数量 <br> - 响应性 从请求到完成一些动作之前的延迟(等待执行的时间) <br> - 可伸缩性 增加资源,提高性能</p><

测试的两个方面:
- 安全性 并发不会造成状态错误。
- 活跃度 主要是性能测试
- 吞吐量 段时间定资源内可以处理的任务数量
- 响应性 从请求到完成一些动作之前的延迟(等待执行的时间)
- 可伸缩性 增加资源,提高性能

正确性测试

所有加入队列的都会被执行:
一般的可行的办法是把加入队列的列表和消费的列表保存起来进行比较。但是因为会设计资源的并发,影响对本身的测试,比较好的办法是在队列中加入唯一的id,然后对id求和,消费时同样求和,来比较结果。这样能最小的影响实际要测试的结果。

public class PutTakeTest {
    private static final ExecutorService pool = Executors.newCachedThreadPool();
    private final AtomicInteger putSum = new AtomicInteger(0);
    private final AtomicInteger takeSum = new AtomicInteger(0);
    private final int nTrials, nPairs;
    private final BlockingQueue<Integer> queue;

    public static void main(String[] args) {
        new PutTakeTest(10000).test();
    }

    public PutTakeTest(int nTrials){
        nPairs = 10;    // 生产者及消费者的个数
        this.nTrials = nTrials;     // 每次生产或者消费多少个
        queue = new ArrayBlockingQueue<Integer>(10);
    }

    public void test(){
        for (int i = 0; i < nPairs; i++) {
            pool.execute(new Producer());
            pool.execute(new Consumer());
        }
        pool.shutdown();
        try {
            pool.awaitTermination(10, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(putSum.get());
        System.out.println(takeSum.get());
    }

    class Producer implements Runnable{
        @Override
        public void run() {
            int sum = 0;
            try {
                for (int i = 0; i < nTrials; i++) {
                    int seed = new Random().nextInt(10000);     // 随机数,用来做sum,最后跟消费者的sum做比较来确定所有入队的都已经被出队消费
                    sum += seed;
                    queue.put(seed);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            putSum.getAndAdd(sum);
        }
    }

    class Consumer implements Runnable{

        @Override
        public void run() {
            int sum = 0;
            try {
                for (int i = 0; i < nTrials; i++) {
                    int seed = queue.take();
                    sum += seed;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            takeSum.getAndAdd(sum);
        }
    }
}

按照上面的代码,实际上出于并行状态的线程并不多,可以使用关卡这种类型的信号量,来让所有的线程同时启动,再同时计算,提升并发的操作。

性能

吞吐量
基于上面的代码,其实在最开始和最后加入时间差的计算就可以粗略估算了
另外还可以借助关卡的特性,在最后回调的时候得到时间
响应性
即完成一个任务所需要的时间

性能测试陷阱

如果测试过程中恰巧多次出发了垃圾回收,那么就有可能把gc的时间算到实际运行的实践中。解决办法
- 使用-verbose:gc来停止垃圾回收的运行
- 第二种就是运行足够长的时间了
另外动态编译也可能会造成数据的不准确,可以使用-xx:+PrintCompilation来查看动态编译的时间,长时间运行测试程序,减少动态编译的影响
另外要考虑不且实际的竞争程度, 影响吞吐量通常是因为边界清晰小人物,大部分的时间都来源于上线问切换,而对于一些锁竞争比较多的程序可能影响最大的是锁竞争的程度,要根据不同情况制定具体的策略。

代码检查

  • 调用Thread.run,应该是.start
  • 显示锁未释放
  • 空synchronized块
  • 双检查锁, 因为可见性的问题及重排序的问题
  • 从构造函数中启动线程,造成了this的溢出
  • notify通常伴随着状态改变使用
  • wait方法通常会出现在持有锁,循环以及含有测试某个状态的谓词(if())
  • Thread.sleep会持有锁会对活跃度造成影响要注意
  • 忙等待 while(a.equals(“”))这样的结果,如果域不是volatile的可能不会及时得到状态变更,可以使用锁通知等更好的方式。
相关文章
|
7月前
|
SQL 安全 测试技术
Web应用程序安全测试
Web应用程序安全测试
190 0
|
7月前
|
存储 缓存 监控
Web 应用程序性能测试核心步骤
Web 应用程序性能测试核心步骤
|
7月前
|
Linux Android开发
测试程序之提供ioctl函数应用操作GPIO适用于Linux/Android
测试程序之提供ioctl函数应用操作GPIO适用于Linux/Android
123 0
|
7月前
|
开发框架 测试技术 定位技术
如何开展移动应用程序性能测试?
如何开展移动应用程序性能测试?
|
2月前
|
安全 Linux 网络安全
Kali渗透测试:远程控制程序基础
Kali渗透测试:远程控制程序基础
Kali渗透测试:远程控制程序基础
|
2月前
|
安全 Java Linux
Kali渗透测试:通过Web应用程序实现远程控制
Kali渗透测试:通过Web应用程序实现远程控制
百万并发连接的实践测试02
百万并发连接的实践测试02
|
4月前
|
网络协议 Ubuntu
百万并发连接的实践测试01
百万并发连接的实践测试01
|
5月前
|
开发框架 JSON 前端开发
基于ABP框架的SignalR,使用Winform程序进行功能测试
基于ABP框架的SignalR,使用Winform程序进行功能测试
|
5月前
|
运维 监控 大数据
部署-Linux01,后端开发,运维开发,大数据开发,测试开发,后端软件,大数据系统,运维监控,测试程序,网页服务都要在Linux中进行部署
部署-Linux01,后端开发,运维开发,大数据开发,测试开发,后端软件,大数据系统,运维监控,测试程序,网页服务都要在Linux中进行部署
下一篇
无影云桌面