白盒测试中如何实现真正意义上并发测试(Java)

在这个话题开始之前,首先我们来弄清楚为什么要做并发测试?

一般并发测试,是指模拟并发访问,测试多用户并发访问同一个应用、模块、数据时是否产生隐藏的并发问题,如内存泄漏、线程锁、资源争用问题。

站在性能测试的角度,并发测试不是为了获得性能指标,而是为了发现并发引起的问题。

那么并发对应的技术实现到底是怎样的呢?

简单地说,并发是指多个进程或线程在某一时刻同时处理指定的操作,有点类似于性能测试中集合点的概念,讲究同时性。

普及到这里,接下来讨论技术实现:

最近在项目里面发现一些开发人员做动态测试模拟500并发时,实现代码如下:

代码片段1:

public static void main(String[] args) {
        // TODO Auto-generated method stub
        for(int i=0;i<500;i++){
            new MyThread().run();
        }
    }

    static class MyThread implements Runnable{

        @Override
        public void run() {
            // TODO Auto-generated method stub
            // 定义每个线程负责的业务逻辑实现
        }
    }

因为涉及一些共享对象的使用,避免多线程乱序现象,我建议加上同步锁,后来开发人员改写了代码,实现如下:

代码片段2:

public static void main(String[] args) {
        // TODO Auto-generated method stub
        // 定义线程池,模拟500并发请求
        ThreadPoolExecutor executor = new ThreadPoolExecutor(500, 500, 1000,
                TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(500),
                new ThreadPoolExecutor.DiscardOldestPolicy());

        for(int i=0;i<500;i++){
            executor.execute(new MyThread());
        }

        executor.shutdown();
    }

    static class MyThread implements Runnable{

        @Override
        public void run() {
            // TODO Auto-generated method stub
            // 定义每个线程负责的业务逻辑实现
            synchronized (this) {

            }
        }
    }

其实上述这种方式在CPU层面采用的是FIFO策略(先进先出),线程是依次拿到锁资源进行处理的,无法达到同时性,所以我决定自己来做白盒测试,使用下面2种方式来实现:CyclicBarrier 和 CountDownLatch .

代码片段3:

public static void main(String[] args) {
        // TODO Auto-generated method stub
        CountDownLatch cdl = new CountDownLatch(500);
        for (int i = 0; i < 500; i++) {
            new MyThread(cdl).run();
        }
        try {
            cdl.await();//调用await()方法的线程会被挂起,它会等待直到count值为0才继续执行
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    static class MyThread implements Runnable {
        private CountDownLatch cdl;

        public MyThread(CountDownLatch cdl) {
            this.cdl = cdl;
        }
        @Override
        public void run() {
            // TODO Auto-generated method stub
            cdl.countDown();//将count值减1
            // 定义每个线程负责的业务逻辑实现
        }
    }

上面每个线程都共享了一个计数器,减1后调用await()方法挂起,直到count减为0时,才一起继续执行;

代码片段4:

public static void main(String[] args) {
        // TODO Auto-generated method stub
        CyclicBarrier cb = new CyclicBarrier(500);
        ExecutorService es = Executors.newFixedThreadPool(500);
        for (int i = 0; i < 500; i++) {
            es.execute(new MyThread(cb));
        }
        es.shutdown();
    }

    static class MyThread implements Runnable {
        private CyclicBarrier cb;

        public MyThread(CyclicBarrier cb) {
            this.cb = cb;
        }
        @Override
        public void run() {
            // TODO Auto-generated method stub
            try {
                // 等待所有任务准备就绪
                cb.await();
                // 定义每个线程负责的业务逻辑实现
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

所有线程创建完毕后调用await()方法挂起,直至所有线程都到达barrier状态再同时执行;

声明:在这里,CyclicBarrier的barrier状态是可重用的,而CountDownLatch是不可重用的,个人还是推荐CyclicBarrier,因为性能上损耗较小些!

今天就总结到这了~~

  • 3
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值