并发压测java脚本你必定要会的3个类

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


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


1CountDownLanch数据库


场景编程

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


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

先看看CountDownLanch提供的方法。app

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

countDown: 将当前的计数减1。ide

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((long10000);
                        // 访问完后,释放
                        semp.release();
                    } catch (InterruptedException e) {
                    }
                }
            };
            exec.execute(run);
        }

        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // System.out.println(semp.getQueueLength());
        // 退出线程池
        exec.shutdown();
    }
}


不知道,你有没有理解,在此也只是抛砖引玉一下,你们在实践中能够继续学习研究。

更多其余测试内容能够参考连接文末更多测试好文章

相关文章
相关标签/搜索