手寫java性能測(cè)試框架第二版
引言
依照領(lǐng)導(dǎo)要求區(qū)分了兩種壓測(cè)模式:固定次數(shù)壓測(cè)和固定時(shí)間壓測(cè)。此前一直沿用的都是固定次數(shù),所以本次第二版剝離了固定次數(shù)的模式增加了固定時(shí)間的模式。
這是第一版:性能測(cè)試框架
第二版的threadbase代碼如下
package com.fun.base.constaint;
import com.fun.frame.SourceCode;
import java.util.concurrent.CountDownLatch;
/**
* 多線程任務(wù)基類,可單獨(dú)使用
*/
public abstract class ThreadBase<T> extends SourceCode implements Runnable {
/**
* 計(jì)數(shù)鎖
* <p>
* 會(huì)在concurrent類里面根據(jù)線程數(shù)自動(dòng)設(shè)定
* </p>
*/
CountDownLatch countDownLatch;
/**
* 用于設(shè)置訪問(wèn)資源
*/
public T t;
protected ThreadBase() {
super();
}
/**
* groovy無(wú)法直接訪問(wèn)t,所以寫了這個(gè)方法
*
* @return
*/
public String getT() {
return t.toString();
}
/**
* 運(yùn)行待測(cè)方法的之前的準(zhǔn)備
*/
protected abstract void before();
/**
* 待測(cè)方法
*
* @throws Exception
*/
protected abstract void doing() throws Exception;
/**
* 運(yùn)行待測(cè)方法后的處理
*/
protected abstract void after();
public void setCountDownLatch(CountDownLatch countDownLatch) {
this.countDownLatch = countDownLatch;
}
}
固定次數(shù)模式的壓測(cè)虛擬類
package com.fun.base.constaint;
import com.fun.frame.excute.Concurrent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import static com.fun.utils.Time.getTimeStamp;
/**
* 請(qǐng)求時(shí)間限制的多線程類,限制每個(gè)線程執(zhí)行的次數(shù)
*
* <p>
* 通常在測(cè)試某項(xiàng)用例固定時(shí)間的場(chǎng)景下使用,可以提前終止測(cè)試用例
* </p>
*
* @param <T> 閉包參數(shù)傳遞使用,Groovy腳本會(huì)有一些兼容問(wèn)題,部分對(duì)象需要tostring獲取參數(shù)值
*/
public abstract class ThreadLimitTimes<T> extends ThreadBase {
private static final Logger logger = LoggerFactory.getLogger(ThreadLimitTimes.class);
/**
* 任務(wù)請(qǐng)求執(zhí)行次數(shù)
*/
public int times;
/**
* 用于設(shè)置訪問(wèn)資源
*/
public T t;
public ThreadLimitTimes(T t, int times) {
this(times);
this.t = t;
}
public ThreadLimitTimes(int times) {
this();
this.times = times;
}
protected ThreadLimitTimes() {
super();
}
/**
* groovy無(wú)法直接訪問(wèn)t,所以寫了這個(gè)方法
*
* @return
*/
public String getT() {
return t.toString();
}
@Override
public void run() {
try {
before();
List<Long> t = new ArrayList<>();
long ss = getTimeStamp();
for (int i = 0; i < times; i++) {
long s = getTimeStamp();
doing();
long e = getTimeStamp();
t.add(e - s);
}
long ee = getTimeStamp();
logger.info("執(zhí)行次數(shù):{},總耗時(shí):{}", times, ee - ss);
Concurrent.allTimes.addAll(t);
} catch (Exception e) {
logger.warn("執(zhí)行任務(wù)失敗!", e);
} finally {
if (countDownLatch != null)
countDownLatch.countDown();
after();
}
}
/**
* 運(yùn)行待測(cè)方法的之前的準(zhǔn)備
*/
protected abstract void before();
/**
* 待測(cè)方法
*
* @throws Exception
*/
protected abstract void doing() throws Exception;
/**
* 運(yùn)行待測(cè)方法后的處理
*/
protected abstract void after();
}固定時(shí)間模式虛擬類
package com.fun.base.constaint;
import com.fun.frame.excute.Concurrent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import static com.fun.utils.Time.getTimeStamp;
/**
* 請(qǐng)求時(shí)間限制的多線程類,限制每個(gè)線程執(zhí)行的時(shí)間
* <p>
* 通常在測(cè)試某項(xiàng)用例固定時(shí)間的場(chǎng)景下使用,可以提前終止測(cè)試用例
* </p>
*
* @param <T> 閉包參數(shù)傳遞使用,Groovy腳本會(huì)有一些兼容問(wèn)題,部分對(duì)象需要tostring獲取參數(shù)值
*/
public abstract class ThreadLimitTime<T> extends ThreadBase {
/**
* 全局的時(shí)間終止開(kāi)關(guān)
*/
private static boolean key = false;
private static final Logger logger = LoggerFactory.getLogger(ThreadLimitTime.class);
/**
* 任務(wù)請(qǐng)求執(zhí)行時(shí)間,單位是秒
*/
public int time;
/**
* 用于設(shè)置訪問(wèn)資源
*/
public T t;
public ThreadLimitTime(T t, int time) {
this(time);
this.t = t;
}
public ThreadLimitTime(int time) {
this();
this.time = time * 1000;
}
protected ThreadLimitTime() {
super();
}
@Override
public void run() {
try {
before();
List<Long> t = new ArrayList<>();
long ss = getTimeStamp();
while (true) {
long s = getTimeStamp();
doing();
long e = getTimeStamp();
t.add(e - s);
if ((e - ss) > time || key) break;
}
long ee = getTimeStamp();
logger.info("執(zhí)行時(shí)間:{} s,總耗時(shí):{}", time / 1000, ee - ss);
Concurrent.allTimes.addAll(t);
} catch (Exception e) {
logger.warn("執(zhí)行任務(wù)失??!", e);
} finally {
if (countDownLatch != null)
countDownLatch.countDown();
after();
}
}
/**
* 用于在某些情況下提前終止測(cè)試
*/
public static void stopAllThread() {
key = true;
}
}這里我多加了一個(gè)終止測(cè)試的key,暫時(shí)沒(méi)有用,以防萬(wàn)一。之所以沒(méi)有采用另起線程去計(jì)時(shí)原因有二:進(jìn)行測(cè)試過(guò)程中無(wú)論如何都會(huì)記錄時(shí)間戳,多余的計(jì)算比較時(shí)間戳大小消耗性能很低,可以忽略;另起線程設(shè)計(jì)麻煩,在發(fā)生意外情況時(shí)缺少第二種保險(xiǎn)措施。
HTTPrequestbase為基礎(chǔ)的多線程類
下面是兩種實(shí)現(xiàn)類的Demo,以HTTPrequestbase作為基礎(chǔ)的多線程類。
固定次數(shù)模式的多線程類
/**
* http請(qǐng)求多線程類
*/
public class RequestThreadTimes extends ThreadLimitTimes {
static Logger logger = LoggerFactory.getLogger(RequestThreadTimes.class);
/**
* 請(qǐng)求
*/
public HttpRequestBase request;
/**
* 單請(qǐng)求多線程多次任務(wù)構(gòu)造方法
*
* @param request 被執(zhí)行的請(qǐng)求
* @param times 每個(gè)線程運(yùn)行的次數(shù)
*/
public RequestThreadTimes(HttpRequestBase request, int times) {
this.request = request;
this.times = times;
}
@Override
public void before() {
GCThread.starts();
}
@Override
protected void doing() throws Exception {
getResponse(request);
}
@Override
protected void after() {
GCThread.stop();
}
/**
* 多次執(zhí)行某個(gè)請(qǐng)求,但是不記錄日志,記錄方法用 loglong
* <p>此方法只適應(yīng)與單個(gè)請(qǐng)求的重復(fù)請(qǐng)求,對(duì)于有業(yè)務(wù)聯(lián)系的請(qǐng)求暫時(shí)不能適配</p>
*
* @param request 請(qǐng)求
* @throws IOException
*/
void getResponse(HttpRequestBase request) throws IOException {
CloseableHttpResponse response = ClientManage.httpsClient.execute(request);
String content = FanLibrary.getContent(response);
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK)
logger.warn("響應(yīng)狀態(tài)碼:{},響應(yīng)內(nèi)容:{}", content, response.getStatusLine());
response.close();
}
}固定時(shí)間模式的多線程類
package com.fun.frame.thead;
import com.fun.base.constaint.ThreadLimitTime;
import com.fun.frame.httpclient.ClientManage;
import com.fun.frame.httpclient.FanLibrary;
import com.fun.frame.httpclient.GCThread;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpRequestBase;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
/**
* http請(qǐng)求多線程類
*/
public class RequestThreadTime extends ThreadLimitTime {
static Logger logger = LoggerFactory.getLogger(RequestThreadTime.class);
/**
* 請(qǐng)求
*/
public HttpRequestBase request;
/**
* 單請(qǐng)求多線程多次任務(wù)構(gòu)造方法
*
* @param request 被執(zhí)行的請(qǐng)求
* @param times 每個(gè)線程運(yùn)行的次數(shù)
*/
public RequestThreadTime(HttpRequestBase request, int time) {
this.request = request;
this.time = time;
}
@Override
public void before() {
GCThread.starts();
}
@Override
protected void doing() throws Exception {
getResponse(request);
}
@Override
protected void after() {
GCThread.stop();
}
/**
* 多次執(zhí)行某個(gè)請(qǐng)求,但是不記錄日志,記錄方法用 loglong
* <p>此方法只適應(yīng)與單個(gè)請(qǐng)求的重復(fù)請(qǐng)求,對(duì)于有業(yè)務(wù)聯(lián)系的請(qǐng)求暫時(shí)不能適配</p>
*
* @param request 請(qǐng)求
* @throws IOException
*/
void getResponse(HttpRequestBase request) throws IOException {
CloseableHttpResponse response = ClientManage.httpsClient.execute(request);
String content = FanLibrary.getContent(response);
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK)
logger.warn("響應(yīng)狀態(tài)碼:{},響應(yīng)內(nèi)容:{}", content, response.getStatusLine());
response.close();
}
}
其中可以發(fā)現(xiàn),差別就在于屬性time還是times的設(shè)定。
使用Demo:
package com.fun;
import com.fun.base.constaint.ThreadLimitTime;
import com.fun.frame.SourceCode;
import com.fun.frame.excute.Concurrent;
import java.util.ArrayList;
import java.util.List;
public class AR extends SourceCode {
public static void main(String[] args) {
ThreadLimitTime<Object> threadLimitTime = new ThreadLimitTime<Object>(10) {
/**
* 運(yùn)行待測(cè)方法的之前的準(zhǔn)備
*/
@Override
protected void before() {
}
/**
* 待測(cè)方法
*
* @throws Exception
*/
@Override
protected void doing() throws Exception {
AR.test();
}
/**
* 運(yùn)行待測(cè)方法后的處理
*/
@Override
protected void after() {
}
};
new Concurrent(threadLimitTime,5).start();
FanLibrary.testOver();
}
public static void test() {
synchronized (AR.class) {
sleep(100);
output("fun");
}
}
}剩下的mysql和redis以及dubbo的Demo就不寫了,各位看官看著發(fā)揮即可,更多關(guān)于java性能測(cè)試框架的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java單元測(cè)試Powermockito和Mockito使用總結(jié)
公司單元測(cè)試框架選用了Junit 4.12,Mock框架選用了Mockito和PowerMock,本文主要介紹了Java單元測(cè)試Powermockito和Mockito使用總結(jié),感興趣的可以了解一下2021-09-09
Spring數(shù)據(jù)庫(kù)連接池實(shí)現(xiàn)原理深入刨析
開(kāi)發(fā)web項(xiàng)目,我們肯定會(huì)和數(shù)據(jù)庫(kù)打交道,因此就會(huì)涉及到數(shù)據(jù)庫(kù)鏈接的問(wèn)題。在以前我們開(kāi)發(fā)傳統(tǒng)的SSM結(jié)構(gòu)的項(xiàng)目時(shí)進(jìn)行數(shù)據(jù)庫(kù)鏈接都是通過(guò)JDBC進(jìn)行數(shù)據(jù)鏈接,我們每和數(shù)據(jù)庫(kù)打一次交道都需要先獲取一次鏈接,操作完后再關(guān)閉鏈接,這樣子效率很低,因此就出現(xiàn)了連接池2022-11-11
java json 省市級(jí)聯(lián)實(shí)例代碼
這篇文章介紹了java json 省市級(jí)聯(lián)實(shí)例代碼,有需要的朋友可以參考一下2013-09-09
Netty分布式pipeline管道創(chuàng)建方法跟蹤解析
這篇文章主要為大家介紹了Netty分布式pipeline管道創(chuàng)建方法跟蹤解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-03-03
GC算法實(shí)現(xiàn)篇之并發(fā)標(biāo)記清除
這篇文章主要為大家介紹了GC算法實(shí)現(xiàn)篇之并發(fā)-標(biāo)記-清除,?CMS垃圾收集器在減少停頓時(shí)間上做了很多給力的工作,?大量的并發(fā)線程執(zhí)行的工作并不需要暫停應(yīng)用線程2022-01-01
spring?retry實(shí)現(xiàn)方法請(qǐng)求重試的使用步驟
這篇文章主要介紹了spring?retry實(shí)現(xiàn)方法請(qǐng)求重試及使用步驟,本文分步驟通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-07-07
解決idea 暫存文件或idea切換分支代碼丟失的問(wèn)題
這篇文章主要介紹了解決idea 暫存文件或idea切換分支代碼丟失的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-02-02
JAVA中通過(guò)Hibernate-Validation進(jìn)行參數(shù)驗(yàn)證
這篇文章主要介紹了JAVA中通過(guò)Hibernate-Validation進(jìn)行參數(shù)驗(yàn)證,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04
使用EasyExcel實(shí)現(xiàn)簡(jiǎn)單的Excel表格解析操作
這篇文章主要介紹了如何使用EasyExcel完成簡(jiǎn)單的表格解析操作,同時(shí)實(shí)現(xiàn)了大量數(shù)據(jù)情況下數(shù)據(jù)的分次批量入庫(kù),并記錄每條數(shù)據(jù)入庫(kù)的狀態(tài),感興趣的可以了解下2025-03-03

