Java TPS实现

来源:互联网 发布:淘宝进口零食推荐 知乎 编辑:程序博客网 时间:2024/06/07 20:54

写在前面

TPS即每秒查询事物,可以用于测试一个方法、工具或者系统的性能。本文采用Java并发包中的工具实现了一个工具TPS性能测试。主要是测试OKHttp库来执行Http请求的性能。测试代码用到了Java了线程池ExecuterServiceCountDownLatch, CyclicBarrier, 原子类,volatile关键词等。可算是对Java并发组件的组合使用。下面直接贴出源码,仅供参考,如有错误,欢迎指出,以期共同探讨。

TPS 实现源码

package cn.concurrent;import java.math.RoundingMode;import java.util.concurrent.*;import java.util.concurrent.atomic.AtomicInteger;import java.util.concurrent.atomic.AtomicLong;import util.OkHttpUtil;import com.google.common.math.LongMath;/** * 每秒事物执行次数统计 *  * @author Xie le * @date 2016/7/9 */public class TpsWorkbeanch {    /** 线程数量 */    public static final int N_THRESHOLDS = 5;    /** 30 秒总时间 */    public static final int TIME_THRESHOLDS = 30;    /** 用原子变量来统计执行时间,便于作原子递减 */    private static AtomicInteger totalTime = new AtomicInteger(TIME_THRESHOLDS);    /** 用于统计执行的事物总数,用原子方式累加记录 */    private static AtomicLong totalExecCount = new AtomicLong(0L);    /** 需要到等到所有线程都在同一起跑线,才开始统计计数,类似于发令枪 */    private static CyclicBarrier barrier = new CyclicBarrier(N_THRESHOLDS);    /** 执行时间到达时,所有的线程需要依次退出,主线程才开始统计执行事物总数 */    private static CountDownLatch countDownLatch = new CountDownLatch(N_THRESHOLDS);    /** 线程执行标记 , 用volatile修饰,使变量修改具有线程可见性 */    private static volatile boolean runnning = true;    /** 用线程池来执行统计 */    private static ExecutorService executorService;    /**     * 用接口来作模拟统计     */    interface Job {        void execute() throws Exception;    }    /**     * 具体Job,模拟完成一次Http请求 BTW:内部类用static修饰     */    static class JobDetail implements Job {        public void execute() throws Exception {            String run = OkHttpUtil.run("http://publicobject.com/helloworld.txt");        }    }    /**     * Worker执行Job     */    static class Worker implements Runnable {        private Job job;        Worker(Job job) {            this.job = job;        }        // 每个线程执行的事物统计量        int innerCount = 0;        public void run() {            try {                barrier.await(); // 等到所有线程都在起跑线                while (runnning) {                    this.job.execute();                    innerCount++;                }            } catch (Exception e) {                System.out.println("线程Id:" + Thread.currentThread().getId() + " " + e.getMessage());            } finally {                // 累加到总记录统计量                System.out.println("线程Id:" + Thread.currentThread().getId() + " 执行事物次数为:" + innerCount);                totalExecCount.getAndAdd(innerCount);                // 线程结束后,依次计数, 便于主线程继续执行                countDownLatch.countDown();            }        }    }    public static void run() throws Exception {        Job job = new JobDetail(); // 创建Job        executorService = Executors.newFixedThreadPool(N_THRESHOLDS); // 新建固定大小线程的池子        for (int i = 0; i < N_THRESHOLDS; i++) {            executorService.submit(new Worker(job)); // 提交线程到池子中        }        // 还需要一个线程,用于周期检查执行时间是否到达        final ScheduledExecutorService scheduledExcutor = Executors.newSingleThreadScheduledExecutor();        scheduledExcutor.scheduleAtFixedRate(new Runnable() {            public void run() {                if (totalTime.decrementAndGet() == 0) { // 执行时间递减到0                    runnning = false; // 告诉线程,时间到了,所有线程不再执行                    scheduledExcutor.shutdownNow();                }            }        }, 1L, 1L, TimeUnit.SECONDS);        // 主线程等到所有的线程都退出,则开始统计        countDownLatch.await();        long totalExeCount = totalExecCount.get();        System.out.println(N_THRESHOLDS + " 个线程," + TIME_THRESHOLDS + " 秒内总共执行的事物数量:" + totalExeCount);        long tps = LongMath.divide(totalExeCount, TIME_THRESHOLDS, RoundingMode.HALF_EVEN);        System.out.println("OKHttp执行的TPS: " + tps);        executorService.shutdownNow(); // 关闭线程池    }    public static void main(String[] args) throws Exception {        run();    }}

其中用到的OKHttp类如下:

package util;import java.io.IOException;import java.util.concurrent.TimeUnit;import okhttp3.OkHttpClient;import okhttp3.Request;import okhttp3.Response;/** * OkHttp工具 * @author Xie le * @date 2016/6/30 */public class OkHttpUtil {    private static OkHttpClient okHttpclient = null;    static {        okHttpclient = new OkHttpClient.Builder()                .connectTimeout(3, TimeUnit.SECONDS)                .build();    }    public static String run(String url) throws Exception {        Request request = new Request.Builder().url(url).build();        Response response = okHttpclient.newCall(request).execute();        if (!response.isSuccessful()) {            throw new IOException("Unexpected code " + response);        }        return response.body().string();    }}

测试结果

测试结果与环境有关。以我本机为例,5个线程,30秒内的测试结果如下:

线程Id:14 connect timed out线程Id:14 执行事物次数为:0线程Id:10 connect timed out线程Id:10 执行事物次数为:0线程Id:11 执行事物次数为:29线程Id:13 执行事物次数为:33线程Id:12 执行事物次数为:265 个线程,30 秒内总共执行的事物数量:88OKHttp执行的TPS: 3

最后

直接阅读代码,可以掌握Java并发的常用的工具类。

2 0
原创粉丝点击