• Jmeter--自己写并发压测脚本一定会遇到的类


    原文链接:https://mp.weixin.qq.com/s?__biz=MzUxMTgyNTQ2MA==&mid=2247484012&idx=1&sn=3a536e9cea99532eaca831c39c9e6620&chksm=f96c8137ce1b0821bdde3b8923ea41578270033a1bbc3ab4c20dc08f88c2ac2f4c817050f243&token=659961685&lang=zh_CN#rd

    性能测试做到后面,一些特殊的场景利用常用的现成工具满足不了需求,所以你需要学习java写一些特定协议的压测脚本,那你不得不研究多线程或线程池,而此时你也一定会遇到java并发编程中的几个类,今天重点讲解这3个类,CountDownLanch、CyclicBarrier、Semaphore,希望大家以后看到的时候知道是干嘛用的。

    接下来,我就最近学习的成果,下面和大家举例子讲解一下,帮助理解。

    1CountDownLanch

    场景

    工作中往往会遇到需要异步处理的任务,此时我们就会利用多线程的方式去处理,即启动子线程去执行任务,而此时主线程阻塞,等待所有的子线程完成任务后,再去做一些汇总统计工作。

    CountDownLanch 是一个倒数计数器, 给一个初始值(>=0), 然后每一次调用countDown就会减1, 这很符合等待多个子线程结束的场景: 一个线程结束的时候, countDown一次, 直到所有的线程都countDown了 , 那么所有子线程就都结束了。

    先看看CountDownLanch提供的方法。

    await: 会阻塞等待计数器减少到0位置. 带参数的await是多了等待时间。

    countDown: 将当前的计数减1。

    getCount(): 返回当前的计数。

    显而易见, 我们只需要在子线程执行之前, 赋予初始化countDownLanch, 并赋予线程数量为初始值。

    每个线程执行完毕的时候, 就countDown一下。主线程只需要调用await方法, 可以等待所有子线程执行结束。

    例子

    package ht.test;
    
    import java.util.concurrent.CountDownLatch;
    import java.util.concurrent.CyclicBarrier;
    
    public class CountDownLatchTest {
    
        // 参数是2表示对象执行2次countDown方法才能释放锁
        static CountDownLatch c = new CountDownLatch(2);
    
        public static void main(String[] args) throws InterruptedException {
            // 定义线程数
            int subThreadNum = 5;
            // 取得一个倒计时器,从5开始
            CountDownLatch countDownLatch = new CountDownLatch(subThreadNum);
            // 依次创建5个线程,并启动
            for (int i = 0; i < subThreadNum; i++) {
                SubThread runnablethread = new SubThread(5000, countDownLatch);
                new Thread(runnablethread).start();
    
            }
            // 主线程工作,此处可以添加一些额外的工作
            // mainWork();
            // 等待所有的子线程结束
            countDownLatch.await();
            System.out.println("all all all Main Thread work done!");
    
        }
    
        static class SubThread implements Runnable {
    
            private CountDownLatch countDownLatch;
            private long workTime;
    
            public SubThread(long workTime, CountDownLatch countDownLatch) {
                this.workTime = workTime;
                this.countDownLatch = countDownLatch;
            }
    
            public void run() {
                // TODO Auto-generated method stub
                try {
                    System.out.println("线程Id:" + Thread.currentThread().getId() + " Sub thread is starting!");
                    Thread.sleep(workTime);
    
                    System.out.println("线程Id:" + Thread.currentThread().getId() + " Sub thread is stopping!");
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } finally {
                    // 线程结束时,将计时器减一
                    countDownLatch.countDown();
                }
            }
        }
    
    }

    2CyclicBarrier

    场景

    我们在做压测的时候,如要真正的并发,那么在创建线程成功后需要等待其他线程也创建好了,一起等着,同时发送请求,此时就用到了CyclicBarrier。

    CyclicBarrier的字面意思是可循环使用(Cyclic)的屏障(Barrier)。它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续运行。

    例子

    package ht.test;
    
    import java.util.concurrent.CyclicBarrier;
    
    public class CyclicBarrierTest {
    
        // 初始化线程等待的个数,当调用await()函数的次数和这里的数值一致时候,接下去执行。
        static CyclicBarrier c = new CyclicBarrier(2);
    
        public static void main(String[] args) throws Exception {
    
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        // 子线程
                        c.await();
    
                    } catch (Exception e) {
    
                    }
                    System.out.println(1);
                }
            }).start();
    
            try {
                // 主线程,若此处注册掉,执行结果为2,并且子线程一直阻塞着
                c.await();
            } catch (Exception e) {
    
            }
            System.out.println(2);
        }
    }

     

    3Semaphore

    场景

    有时候并发太大的时候,我们需要人工的控制,譬如一些数据库的连接数这样子的,资源毕竟有限的,不可能无限去创建连接,此时我们就需要利用Semaphore去控制。

    Semaphore(信号量)是用来控制同时访问特定资源的线程数量,它通过协调各个线程,以保证合理的使用公共资源。可以控制系统的流量,拿到信号量的线程可以进入,否则就等待。通过acquire()和release()获取和释放访问许可。

    例子

    package ht.test;
    
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Semaphore;
    
    public class TestSemaphore {
        public static void main(String[] args) {
            // 线程池
            ExecutorService exec = Executors.newCachedThreadPool();
            // 只能5个线程同时访问
            final Semaphore semp = new Semaphore(5);
            // 模拟20个客户端访问
            for (int index = 0; index < 20; index++) {
                final int NO = index;
                Runnable run = new Runnable() {
                    @Override
                    public void run() {
                        try {
                            // 获取许可
                            semp.acquire();
                            System.out.println("Accessing: " + NO);
                            // 模拟实际业务逻辑
                            Thread.sleep((long) 10000);
                            // 访问完后,释放
                            semp.release();
                        } catch (InterruptedException e) {
                        }
                    }
                };
                exec.execute(run);
            }
    
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            // System.out.println(semp.getQueueLength());
            // 退出线程池
            exec.shutdown();
        }
    }

    不知道,你有没有理解,在此只是抛砖引玉一下,大家在实践中可以继续学习研究。

  • 相关阅读:
    IDEA操作git的一些常用技巧
    实现多Realm时,可能会出现的问题
    Solr入门-Solr服务安装(windows系统)
    ES6中的Set和Map集合
    ES6中的类
    ES6数组扩展
    ES6定型数组
    Promise和异步编程
    深入理解ajax系列第八篇
    深入理解ajax系列第六篇
  • 原文地址:https://www.cnblogs.com/yimai-series/p/13639783.html
Copyright © 2020-2023  润新知