Java模拟并发请求,并统计请求的平均响应时间(CountDownLatch)

 

背景

做实验过程中,想统计某个接口在并发请求的情况下的平均响应时间,如何用Java去实现这个功能呢?

技术实现


 一、可能遇到的问题


1、我们可以利用多线程去实现,只要多开几个线程,发起请求就好了,但是这不是真正的并发!因为线程的创建是有先后顺序的,这样做本质还是先创建的线程先执行。
2、操作系统对线程的调度我们是不知道的,我们该如何实现,主线程等待所有子线程执行完毕后,才去统计子线程耗时呢

这里就要用到Java中的CountDownLatch类。

二、什么是countDownlatch


CountDownLatch是一个同步工具类,它通过一个计数器来实现的,初始值为线程的数量。每当一个线程完成了自己的任务,计数器的值就相应得减1。当计数器到达0时,表示所有的线程都已执行完毕,然后在等待的线程就可以恢复执行任务。

关键方法:


countDown(): 每调用一次计数器值-1,直到count被减为0,代表所有线程全部执行完毕。
await(): 等待计数器变为0,即等待所有异步线程执行完毕。

二、利用countDownlatch实现多个线程同时启动


1、实现自定义任务线程

public class MyConcurrentThreadHcode implements Callable<Long> {
    private final CountDownLatch latch;
    private final CountDownLatch latchTotal;

    public MyConcurrentThreadHcode(CountDownLatch latch, CountDownLatch latchTotal) {
        this.latch = latch;
        this.latchTotal = latchTotal;
    }

    public Long call() {
        System.out.println(Thread.currentThread().getName()+",prepare at: "+System.currentTimeMillis());
        try {
            //先阻塞在这里,等待主线程将latch的计数器减为0
            latch.await();
            return doTask();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            //执行完一次latchTotal的计数器减一,latchTotal减到0后,主线程才会继续往下执行
            latchTotal.countDown();
        }
        return -1L;
    }


    public long doTask()  {
        Map<String, Object> params = new HashMap<String, Object>(7);

        params.put("minX", -68.8);
        params.put("maxX", -65);
        params.put("minY", 17);
        params.put("maxY", 20);
        params.put("startTimeStr", "2022-01-03T00:00:00");
        params.put("endTimeStr", "2022-01-03T10:00:00");

        long startTime = System.currentTimeMillis();
        String result = HttpUtil.get("http://localhost:6068/test/QueryByHCode", params);
        long endTime = System.currentTimeMillis();
 
        return endTime - startTime;
    }
}

2、主线程创建多线程,并同时启动

 public static void testConcurrentWCodeQuery(int totalThreadNum) throws ExecutionException, InterruptedException {
        //01 创建指定threadNum个数的线程
        CountDownLatch latchTotal = new CountDownLatch(totalThreadNum);
        CountDownLatch latch = new CountDownLatch(1);
        List<FutureTask> tasks = new ArrayList<>(totalThreadNum);
        for (int i = 0; i < totalThreadNum ; i++) {
            MyConcurrentThreadWcode task = new MyConcurrentThreadWcode(latch, latchTotal);
            FutureTask futureTask = new FutureTask(task);
            tasks.add(futureTask);
            Thread thread = new Thread(futureTask);
            thread.start();
        }
        //同时启动多个线程
        latch.countDown();

        try {
            /**所有子线程未执行完,主线程会阻塞在这里*/
            latchTotal.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


        long totalTime = 0L;
        int num = 0;
        for(FutureTask task : tasks)
        {
            Long time = (Long)task.get();
            if(time > 0L){
                totalTime += time;
                num ++;
            }
        }
        System.out.println("查询平均耗时:" + totalTime/num + "ms");
    }

在主线程和任务线程中,创建了两个CountDownLatch变量,一个变量latch的初始计数器为1,变量latchTotal的初始计数器为线程数。

latch变量的作用是在主线程创建完所有子线程后,再启动子线程
latchTotal变量的作用是在子线程执行完所有任务后,在执行主线程代码

如此,便能实现多个线程同时启动,并在所有子线程执行完毕之后,统计其总耗时。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值