前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >如何编写一套多线程的测试用例?

如何编写一套多线程的测试用例?

作者头像
Java极客技术
发布2022-12-04 14:04:26
6680
发布2022-12-04 14:04:26
举报
文章被收录于专栏:Java极客技术Java极客技术

一、摘要

很多时候,新开发的功能在上线之前,我们都会进行压力测试,以防上线之后,突然出现性能瓶颈或者出现线程安全问题。

那么问题来了,如何进行压力测试呢?

实践的手段有很多种,比如采用 jmeter 、fiddler、postman 等第三方工具,可以快速实现性能压力测试。

当然除此之外,其实我们也利用 java 的多线程特性,完全可以自行编写一套多线程的压力测试。

下面我们以访问百度首页服务为例,向大家演示一下,采用 java 的多线程特性,该如何编写并发测试。

二、代码实践

2.1、方案一

说到多线程,大家可能想到的就是实例化一个Thread对象,然后启动它,就可以实现异步处理,以模拟100个用户同时请求百度首页为例,代码实践如下:

public static void main(String[] args) throws InterruptedException {
    //模拟100个线程,同时请求百度首页
    long start = System.currentTimeMillis();
    final int threadNum = 100;
    final CountDownLatch countDownLatch = new CountDownLatch(threadNum);
    for (int i = 0; i < threadNum; i++) {
        final int threadCount = i + 1;
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("thread " + threadCount + " start");
                //访问百度首页
                String url = "https://www.baidu.com";
                String rs = HttpUtils.getUrl(url);
                System.out.println("thread " + threadCount + " run result:" + rs);
                System.out.println("thread " + threadCount + " final");
                //执行完成之后,计数器减一
                countDownLatch.countDown(); 
            }
        }).start();    }
    //线程同步阻塞
    countDownLatch.await();
    System.out.println("执行耗时:" + (System.currentTimeMillis() - start) + "ms");
}

实践过程非常简单,采用Thread + CountDownLatch组合,进行阻塞测试。

但是实际上往往我们进行多线程模拟用户进行访问某个服务的时候,每个用户的请求参数是不一样的,这个时候我们应该如何更加真实的贴近用户实际请求去测试呢?请看下面这个方案!

2.1、方案二

实际上在多线程并发编程中,它还有一个完美搭档,那就是队列,采用多线程+队列组合编程模型,可以实现带任务的异步处理,并且性能高效!

下面我们还是以访问百度首页服务为例,采用多线程+队列组合模式来模拟 100 个用户总共发起了1000次访问百度首页,代码实践如下!

public static void main(String[] args) throws InterruptedException {
    //将每个用户访问百度服务的请求参数,存入阻塞队列BlockingQueue中
    BlockingQueue<String> queue = new LinkedBlockingQueue<>();
    for (int i = 0; i < 1000; i++) {
        queue.put("https://www.baidu.com?paramKey=" + i);
    }

    //模拟100个线程,执行1000次请求访问百度
    long start = System.currentTimeMillis();
    final int threadNum = 100;
    final CountDownLatch countDownLatch = new CountDownLatch(threadNum);
    for (int i = 0; i < threadNum; i++) {
        final int threadCount = i + 1;
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("thread " + threadCount + " start");
                boolean over = false;
                while (!over) {
                    String url = queue.poll();
                    if(Objects.nonNull(url)) {
                        //发起请求
                        String result =HttpUtils.getUrl(url);
                        System.out.println("thread " + threadCount + " run result:" + result);
                    }else {
                        //任务结束
                        over = true;
                        System.out.println("thread " + threadCount + " final");
                        countDownLatch.countDown();
                    }
                }
            }
        }).start();
    }
    countDownLatch.await();
    System.out.println("执行耗时:" + (System.currentTimeMillis() - start) + "ms");
}

当然,你还可以自由调整线程数,也可以采用juc包的线程池来实现多线程编程,改造逻辑如下:

public static void main(String[] args) throws InterruptedException {
    //将每个用户访问百度服务的请求参数,存入阻塞队列BlockingQueue中
    BlockingQueue<String> queue = new LinkedBlockingQueue<>();
    for (int i = 0; i < 1000; i++) {
         queue.put("https://www.baidu.com?paramKey=" + i);
    }

    //模拟100个线程,执行1000次请求访问百度
    long start = System.currentTimeMillis();
    final int threadNum = 100;
    //线程计数器
    final CountDownLatch countDownLatch = new CountDownLatch(threadNum);
    //执行线程池
    ExecutorService fixedThreadPool = Executors.newFixedThreadPool(threadNum);
    for (int i = 0; i < threadNum; i++) {
        final int threadCount = i + 1;
        fixedThreadPool.execute(new Runnable() {
            @Override
            public void run() {
                System.out.println("thread " + threadCount + " start");
                boolean over = false;
                while (!over) {
                    String url = queue.poll();
                    if(Objects.nonNull(url)) {
                        //发起请求
                        String result =HttpUtils.getUrl(url);
                        System.out.println("thread " + threadCount + " run result:" + result);
                    }else {
                        //任务结束
                        over = true;
                        System.out.println("thread " + threadCount + " final");
                        countDownLatch.countDown();
                    }
                }
            }
        });
    }
    countDownLatch.await();
    fixedThreadPool.shutdown();
    System.out.println("执行耗时:" + (System.currentTimeMillis() - start) + "ms");
}

其中BlockingQueue阻塞队列,支持线程数据共享,当一个线程把数据取出之后,另一个线程无法再取,最后的运行效果是一样的!

三、小结

本文主要围绕采用多线程编程,实现服务性能压力测试进行案例介绍,如果有描述不对的地方,欢迎网友批评指出!

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-10-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java极客技术 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 二、代码实践
    • 2.1、方案一
      • 2.1、方案二
      • 三、小结
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档