在前面的时间,我分享两篇关于ThreadLocal
类的文章:利用ThreadLocal解决线程同步问题和Java中的ThreadLocal功能演示,今天以之前做过的一个链路性能测试,分享一下在ThreadLocal
在测试中的简单应用。
需求和逻辑
需求
需求是用户(登录状态)对某个资源(通过minisource_id
确认)进行取消收藏和收藏的功能。
业务判断依据为相应结构中在外层JSON
对象的key=meta
的value
为JSON
对象,且value
中的key=ecode
必需为0
。
逻辑
先进行收藏,然后取消收藏,以此作为一个链路进行性能测试。这个例子我在链路压测中如何记录每一个耗时的请求中用到过,感兴趣的可以去看一下。
思路
根据ThreadLocal
类的功能和使用场景,我在功能类OKClass
中初始化了一个超长的minisource_id
的List
对象,用来存储测试可能需要的ids
。然后通过一个线程安全的AtomicInteger
对象标记索引位置,方便在initialValue()
方法中,返回不同的minisource_id
。
具体的规则就是,每执行一次initialValue()
方法,索引index
增加1
,这样可以保证每个线程调用功能类对象的方法时,使用的minisource_id
都是不一样的。
功能类改造
功能类代码比较多,我就把此次修改涉及的代码分享如下:
代码语言:javascript复制 /**
* 所有可用的id
*/
public static List<Integer> ids = RWUtil.readTxtFileByNumLine(getLongFile("ids"))
/**
* 索引标记
*/
public static AtomicInteger index = new AtomicInteger(0)
/**
* 线程不共享对象
*/
public static ThreadLocal<Integer> minisource_id = new ThreadLocal() {
@Override
public Integer initialValue() {
ids.get(index.getAndIncrement())
}
}
/**
* 收藏OK智课
* @param minicourse_id
* @param ktype 0-机构,1-老师
* @return
*/
public JSONObject collect(int minicourse_id = minisource_id.get(), int ktype = 0, int grade_id = 12) {
String url = OKClassApi.COLLECT
def params = getParams()
params.put("minicourse_id", minicourse_id);
params.put("kid_route", [640]);
params.put("ktype", ktype);
params.put("grade_id", grade_id);
params.put("link_source", 1);//0-教师空间,1-教师机
def response = getPostResponse(url, params)
output(response)
response
}
/**
* 取消收藏
* @param minicourse_id
* @param ktype
* @param grade_id
* @return
*/
public JSONObject unCollect(int minicourse_id = minisource_id.get(), int ktype = 0) {
String url = OKClassApi.UNCOLLECT
def params = getParams()
params.put("minicourse_id", minicourse_id);
params.put("kid_route", [82]);
params.put("ktype", ktype);
def response = getPostResponse(url, params)
output(response)
response
}
- 这里的写法有个参数默认值的,这是
Groovy
特性,可以当做params.put("minicourse_id", minisource_id.get());
。
压测脚本
功能不多说了,没有改动,分享如下:
代码语言:javascript复制package com.okayqa.composer.performance.master1_0
import com.fun.base.constaint.ThreadLimitTimesCount
import com.fun.frame.execute.Concurrent
import com.fun.frame.httpclient.ClientManage
import com.fun.utils.ArgsUtil
import com.okayqa.composer.base.OkayBase
import com.okayqa.composer.function.OKClass
import java.util.concurrent.atomic.AtomicInteger
class BothCollect extends OkayBase {
static AtomicInteger u = new AtomicInteger(0)
static int times = 0
static int thread
public static void main(String[] args) {
ClientManage.init(5, 1, 0, "", 0)
def util = new ArgsUtil(args)
thread = util.getIntOrdefault(0, 200)
times = util.getIntOrdefault(1, 100)
def funs = []
thread.times {
funs << new FunTester()
}
new Concurrent(funs, "收藏和取消收藏").start()
allOver()
}
static int getTimes() {
return times
}
static class FunTester extends ThreadLimitTimesCount {
OkayBase okayBase = getBase(u.getAndIncrement())
OKClass driver = new OKClass(okayBase)
public FunTester() {
super(null, getTimes(), null)
}
@Override
protected void doing() {
def collect = driver.collect()
def value = okayBase.getLastRequestId() CONNECTOR
this.threadmark = value
if (collect.getJSONObject("meta").getIntValue("ecode") != 0) fail(value "请求出错!")
def collect1 = driver.unCollect()
def value1 = okayBase.getLastRequestId()
this.threadmark = value1
if (collect1.getJSONObject("meta").getIntValue("ecode") != 0) fail(value1 "请求出错!")
}
}
}