Day4 多线程下对druid的测试

多线程下对druid的测试

今天继续Case2, 和之前的Case0相比呢,是继续比较多个线程池的性能对比。这次不同的是,用100个线程并发去执行25000个数据库的连接并释放。我们今天不研究他们不同线程池的性能对比,研究下这个测试用例用到的多线程,并发相关的东西,看懂这段代码。
在这里插入图片描述
可以看到下面的代码是druid连接池的测试方法,核心方式是p0

   public void test_0() throws Exception {
        DruidDataSource dataSource = new DruidDataSource();

        dataSource.setInitialSize(initialSize);
        dataSource.setMaxActive(maxActive);
        dataSource.setMinIdle(minPoolSize);
        dataSource.setMaxIdle(maxPoolSize);
        dataSource.setPoolPreparedStatements(true);
        dataSource.setDriverClassName(driverClass);
        dataSource.setUrl(jdbcUrl);
        dataSource.setPoolPreparedStatements(true);
        dataSource.setUsername(user);
        dataSource.setPassword(password);
        dataSource.setValidationQuery(validationQuery);
        dataSource.setTestOnBorrow(testOnBorrow);

        for (int i = 0; i < executeCount; ++i) {
            p0(dataSource, "druid", threadCount);
        }
        System.out.println();
    }

AtomicLong & CountDownLatch

在p0中,看到定义了几个并发相关的类,原子类AtomicLong,并发工具类CountDownLatch,看到这两个熟悉又陌生的类差点给我送走,仔细回忆了下。

AtomicLong

AtomicLong是一个线程安全的计数器,不会受多线程的影响。

CountDownLatch

CountDownLatch是,初始一个数量这里面是100,每一次调用CountDown数量都会减1,
调用它的await方法,就会阻塞主线程,等待100归0后,才会继续执行。
如下面的代码中的startLatch,每个子线程的主方法体中,startLatch.await()就是在等待CountDown=0时,所有的子线程一起开始执行方法体的内容。

    private void p0(final DataSource dataSource, String name, int threadCount) throws Exception {

        final CountDownLatch startLatch = new CountDownLatch(1);
        final CountDownLatch endLatch = new CountDownLatch(threadCount);
        final AtomicLong blockedStat = new AtomicLong();
        final AtomicLong waitedStat = new AtomicLong();

        for (int i = 0; i < threadCount; ++i) {
            Thread thread = new Thread() {

                public void run() {
                    try {
                    //每个子线程在等待,统一开始
                        startLatch.await();

                        long threadId = Thread.currentThread().getId();

                        long startBlockedCount, startWaitedCount;
                        {
                            ThreadInfo threadInfo = ManagementFactory.getThreadMXBean().getThreadInfo(threadId);
                            startBlockedCount = threadInfo.getBlockedCount();
                            startWaitedCount = threadInfo.getWaitedCount();
                        }
                        for (int i = 0; i < LOOP_COUNT; ++i) {
                            Connection conn = dataSource.getConnection();
                            conn.close();
                        }

                        ThreadInfo threadInfo = ManagementFactory.getThreadMXBean().getThreadInfo(threadId);
                        long blockedCount = threadInfo.getBlockedCount() - startBlockedCount;
                        long waitedCount = threadInfo.getWaitedCount() - startWaitedCount;

                        blockedStat.addAndGet(blockedCount);
                        waitedStat.addAndGet(waitedCount);
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
                    //每个子线程执行完后,都会-1
                    endLatch.countDown();
                }
            };
            thread.start();
        }
        long startMillis = System.currentTimeMillis();
        long startYGC = TestUtil.getYoungGC();
        long startFullGC = TestUtil.getFullGC();
           //start归0后,所有的子线程开始跑。
        startLatch.countDown();
     //end开始等待。
        endLatch.await();
//等所有子线程跑完每个线程的25000个连接释放,就会回到主线程。继续往下走。
        long millis = System.currentTimeMillis() - startMillis;
        long ygc = TestUtil.getYoungGC() - startYGC;
        long fullGC = TestUtil.getFullGC() - startFullGC;

        System.out.println("thread " + threadCount + " " + name + " millis : "
                           + NumberFormat.getInstance().format(millis) + ", YGC " + ygc + " FGC " + fullGC
                           + " blockedCount " + blockedStat.get() + " waitedCount " + waitedStat.get());
    }

测试指标

blockedCount

这blockedCount是什么意思呢,我去看了下源码中的注释
(被阻止进入锁的次数) Number of times blocked to enter a lock

waitedCount

(等待锁的次数)Number of times waited on a lock

google翻译有点不太清楚。我理解就是blcokedCount是线程阻塞的次数总和。
waitedCount是等待获取锁的次数总和。这两个数值越少,代表数据库连接池的性能越高。

测试结果

可以明显发现druid的blcokedCount才是0或者1,性能非常高。
由于为了弄清楚blockedCount和waitedCount的含义,下次去复习下Thread的状态,和各个状态之间的转换。
在这里插入图片描述
在这里插入图片描述