V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Acceml
V2EX  ›  程序员

[ Java ] CyclicBarrier 在性能测试中的运用

  •  
  •   Acceml ·
    Acceml · 2018-09-04 22:37:17 +08:00 · 1288 次点击
    这是一个创建于 2272 天前的主题,其中的信息可能已经有所发展或是发生改变。

    背景

    前面我们举了一个例子,说明 CountDownLatch 闭锁的运用,本文我们讲解一下 CyclicBarrier 的运用,这两个经常被面试官放在一起问区别,实际上记住和理解我举的这两个例子就基本掌握了它们的区别。

    CyclicBarrier (栅栏)

    CyclicBarrier 类似于闭锁,与闭锁的关键区别在于,闭锁用于等待事件(上次我们的例子中,主线程等待其他 cache 加载完成才继续执行,没加载完成就阻塞主线程),栅栏用于等待其他线程,其作用是让一组线程到达一个屏障时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续运行。CountDownLatch 倾向于一个线程等多个线程,CyclicBarrier 倾向于多个线程互相等待。

    栅栏的作用就类似于运动员赛跑时候的发令枪,裁判没打发令枪之前,谁也不准跑

    应用:性能测试

    考虑这么一个问题,现在要对你们线上的数据库做压测。你可能想到这么几步:

    1. 搭建和线上一样配置的机子;
    2. 模拟线上数据;
    3. 进行读写测试;
    4. 调整读写请求的比例进行测试;
    5. 观察 I/O、MEM、CPU 等指标;
    6. 观察主从节点备份情况。

    第 2 步准备数据的是时候,你起了 1w 个线程去准备数据,但是 load 数据是需要时间的,这个时候如果有的线程先请求了数据库,有的线程后请求数据库,对于数据库的 QPS 就是 < 1w 的,所以需要他们同时并发的去请求。在 load 数据这个阶段我们用 CyclicBarrier 去拦住他们,当所有的线程都 load 好数据之后,同时请求数据库,对数据库进行压测。

    public class CyclicBarrierTest {
        private static CyclicBarrier cyclicBarrier;
    
        public static class PrepareReadDataThread extends Thread {
            private int id;
    
            PrepareReadDataThread(int id) {
                this.id = id;
            }
    
            public void run() {
                try {
                    System.out.println("线程:" + this.id + " 可以读数据啦!");
                    cyclicBarrier.await();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                System.out.println("所有任务完毕,继续处理其他任务... "+System.currentTimeMillis());
            }
        }
    
        public static class PrepareWriteDataThread extends Thread {
            private int id;
    
            PrepareWriteDataThread(int id) {
                this.id = id;
            }
    
            public void run() {
                try {
                    Thread.sleep(3000);
                    System.out.println("线程:" + this.id + " 可以 load 写数据完成!");
                    cyclicBarrier.await();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                System.out.println("所有任务完毕,继续处理其他任务... "+System.currentTimeMillis());
            }
        }
    
    
        public static void main(String[] args) {
            cyclicBarrier = new CyclicBarrier(5, () -> System.out.println("测试开始!"));
            for (int i = 0; i < 5; i++) {
                new PrepareReadDataThread(i).start();
            }
            //重置一下
            cyclicBarrier.reset();
    
            for (int i = 0; i < 5; i++) {
                new PrepareWriteDataThread(i).start();
            }
        }
    }
    
    

    对比

    1.CountDownLatch 的计数器只能使用一次,而 CyclicBarrier 的计数器可以使用 reset()方法重置。所以 CyclicBarrier 能处理更为复杂的业务场景。例如,如果计算发生错误,可以重置计数器,并让线程重新执行一次

    2.CyclicBarrier 还提供其他有用的方法,比如 getNumberWaiting 方法可以获得 Cyclic-Barrier 阻塞的线程数量。isBroken()方法用来了解阻塞的线程是否被中断

    3.CountDownLatch 倾向于一个线程等多个线程,CyclicBarrier 倾向于多个线程互相等待

    相关阅读

    目前尚无回复
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2755 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 07:10 · PVG 15:10 · LAX 23:10 · JFK 02:10
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.