博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java高并发及测试代码
阅读量:6595 次
发布时间:2019-06-24

本文共 8224 字,大约阅读时间需要 27 分钟。

公司的妹子不会做并发测试。做完一名程序猿看着有点干捉急。并发测试是多个人同时访问一个服务,这不就是多线程吗!于是灵光一现使用多线程来写并发测试代码。想想心理都有点小激动咧。效果比工具还好,废话不多说贴代码

添加Maven依赖

<!--添加OKHttp.jar包-->
<dependency>

com.squareup.okhttp3
okhttp
3.8.1

</dependency>

<!-- -->

<dependency>

com.squareup.okio
okio
1.11.0

</dependency>

<dependency>

com.google.code.gson
gson
2.8.0

</dependency>

先封装OKHTTP(使用CallBack思想做的封装),这个很早之前就封装了,公司移动端也是使用OKHTTP做的服务请求调用。经常遇到图片上传不了的问题,报的错是Socket连接超时的问题。解决这个问题so easy,把连接时间(KEEP_ALIVE)时间设置长一点就行了嘛!

OkHttp底层是用socket做的通信,现在很多应该的底层通信都用的Socket,例子不多说,全靠经验。

public abstract class HttpCommon {

/** * 设置连接超时时间为30000秒 */private final static int CONNECT_TIMT_OUT = 30000;/** * 设置写超时时间为30000秒 */private final static int WRITE_TIME_OUT = 30000;static {    final OkHttpClient.Builder httpBuilder = new OkHttpClient.Builder();    okHttpClient = httpBuilder.connectTimeout(CONNECT_TIMT_OUT, TimeUnit.SECONDS)            .writeTimeout(WRITE_TIME_OUT, TimeUnit.SECONDS).build();}public abstract void callBack(String responseString);/** * get请求 * * @param url url地址 * @param map 请求参数 * @return 返回结果。如果为“”表示失败 */public void get(String url, Map
map) { url = wrapUrl(url, map); // 创建请求参数 Request request = new Request.Builder().url(url).build(); //创建请求对象 Call call = okHttpClient.newCall(request); try { Response response = call.execute(); if (response.isSuccessful()) { callBack(response.body().string()); } } catch (IOException e) { e.printStackTrace(); }}/** * post请求 * * @param url post请求的url * @param t post请求的表单实体 * @return 返回结果。如果为“”表示失败 */public
void post(String url, Map
map, T t) { url = wrapUrl(url, map); String json = new Gson().toJson(t); RequestBody body = RequestBody.create(JSON, json); Request request = new Request.Builder().url(url).post(body).build(); Response response = null; try { response = okHttpClient.newCall(request).execute(); if (response.isSuccessful()) { callBack(response.body().string()); } } catch (IOException e) { e.printStackTrace(); }}/** * post请求 * * @param url post请求的url * @param t post请求的表单实体 * @return 返回结果。如果为“”表示失败 */public
void post(String url, T t) { String json = new Gson().toJson(t); RequestBody body = RequestBody.create(JSON, json); Request request = new Request.Builder().url(url).post(body).build(); Response response = null; try { response = okHttpClient.newCall(request).execute(); if (response.isSuccessful()) { callBack(response.body().string()); } } catch (IOException e) { e.printStackTrace(); }}/** * 上传文件请求 * * @param url 请求url * @param map 请求参数 * @param filePath 文件路径 * @return 返回结果。结果为""表示失败 */private void uploadFile(String url, Map
map, String filePath) { url = wrapUrl(url, map); File file = new File(filePath); RequestBody fileBody = RequestBody.create(OCTET, file); RequestBody requestBody = new MultipartBody.Builder().setType(MultipartBody.FORM) .addFormDataPart("image", file.getName(), fileBody).build(); Request request = new Request.Builder().url(url).post(requestBody).build(); execute(request);}/** * 上传多个文件请求 * * @param url 请求url * @param map 请求参数 * @param filePaths 文件路径 * @return 返回结果。结果为""表示失败 */private void uploadFiles(String url, Map
map, List
filePaths) { url = wrapUrl(url, map); MultipartBody.Builder builder = new MultipartBody.Builder(); builder.setType(MultipartBody.FORM); for (String str : filePaths) { File file = new File(str); RequestBody fileBody = RequestBody.create(OCTET, file); builder.addFormDataPart("image", file.getName(), fileBody); } RequestBody requestBody = builder.build(); Request request = new Request.Builder().url(url).post(requestBody).build(); execute(request);}/** * 执行文件上传操作 * * @param request */private void execute(Request request) { try { Response response = okHttpClient.newCall(request).execute(); if (response.isSuccessful()) { callBack(response.body().string()); } } catch (IOException e) { e.printStackTrace(); }}/** * 拼接get请求url * * @param url 请求url * @param map 参数 * @return 返回拼接完的url地址 */private String wrapUrl(String url, Map
map) { if (null == map) { return url; } url += "?"; for (Map.Entry entry : map.entrySet()) { url += entry.getKey() + "=" + entry.getValue() + "&"; } if (url.endsWith("&")) { url = url.substring(0, url.length() - 1); } return url;}/** * 请求客户端 */private static OkHttpClient okHttpClient;/** * Json媒体类型 */private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");/** * 二进制流的媒体类型 */private static final MediaType OCTET = MediaType.parse("application/octet-stream");

}

public class RunThread {

private final String URL;private HttpCommon httpCommon;private int num;private static ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 100, 1000000L, TimeUnit.SECONDS, new LinkedBlockingDeque<>());private CountDownLatch countDownLatch;/** * @param url 服务URL地址, * @param num 并发访问次数,一般配置50+ */public RunThread(String url, int num) {    this.URL = url;    this.num = num;    this.countDownLatch = new CountDownLatch(num);    httpCommon = new HttpCommon() {        @Override        public void callBack(String responseString) {            System.out.println(responseString);        }    };}public void testGet(Map
map) { long startTime = System.currentTimeMillis(); for (int i = 0; i < num; i++) { executor.execute(new Runnable() { @Override public void run() { httpCommon.get(URL, map); countDownLatch.countDown(); } }); } try { countDownLatch.await(); long executeTime = System.currentTimeMillis() - startTime; System.out.println("一共消耗:" + executeTime +"毫秒"); } catch (InterruptedException e) { e.printStackTrace(); }}public
void testPost(Map
map, T t) { long startTime = System.currentTimeMillis(); for (int i = 0; i < num; i++) { executor.execute(new Runnable() { @Override public void run() { httpCommon.post(URL, map, t); countDownLatch.countDown(); } }); } try { countDownLatch.wait(); long executeTime = System.currentTimeMillis() - startTime; System.out.println("一共消耗:" + executeTime +"毫秒"); } catch (InterruptedException e) { e.printStackTrace(); }}

}

public static void main(String[] args) {    String Url = "http://localhost:8085/test/add";    RunThread testMain = new RunThread(Url, 1000);    // 测试Get请求    testMain.testGet(new HashMap<>());

// // 测试POST请求、PUT请求、DELETE请求

// testMain.testPost(new HashMap<>(), null);

}

上面是并发测试代码,那么如何写高并发测试代码呢!想到两点:一个锁、一个事务。先用Oracle做实验。

<insert id="insert" parameterType="int">

insert into testa  (aaaa, bbbb)values  (#{aaa}, #{aaa})

</insert>

<select id="select" resultType="int">

select max(aaaa) from testa

</select>

Service层代码,设置事务的隔离级别为不可重复读
Isolation.REPEATABLE_READ,结果报错“Could not open JDBC Connection for transaction; nested exception is java.sql.SQLException: 仅 READ_COMMITTED 和 SERIALIZABLE 是有效的事务处理级”。卧槽!还能不能一起愉快地玩耍了,Oracle居然只支持可重复读和可系列化两种事务级别,真是让人大跌眼镜。

贴一下高并发代码吧,经过实验,通过1000个并发请求,使用Durid + Lock成功1百个不到(在这里还是得喷一下阿里的技术),使用dbcp2 + Lock成功2百多个,使用dbcp2 + synchronized 竟然成功了940个。

@Autowired
private TestMapper testMapper;

//private Lock lock = new ReentrantLock();

@Transactional(isolation = Isolation.SERIALIZABLE)

public synchronized Integer test(Integer a, Integer b) {

int c = testMapper.select();    c += 1;    testMapper.insert(c);    return c;

}

代码有问题,找找错误原因吧。Spring AOP执行事务,会在Service方法执行之前就开始事务,再执行Synchronized同步方法。这样会导致查询数据并没有做同步,修改成如下代码,能完美解决问题。测试得出如下代码的执行效率最高,1000个并发耗时9018毫秒

@Autowired
private TestMapper testMapper;

//private Lock lock = new ReentrantLock();

public synchronized Integer test(Integer a, Integer b) {

int c = testMapper.select();c += 1;update(c);return c;

}

@Transactional(isolation = Isolation.SERIALIZABLE)

public void update(int c) {

testMapper.insert(c);

}

转载地址:http://rmcio.baihongyu.com/

你可能感兴趣的文章
Cacti部署SOP
查看>>
Extjs - Panel组件
查看>>
收集参数及反转过程
查看>>
PPTP××× 数据分流
查看>>
mongodb 索引
查看>>
Citrix 宣布 XenServer 全面开源
查看>>
我的友情链接
查看>>
oracle 如果为空则输出0
查看>>
Spfa(最短路求解)
查看>>
使用linux-c编程实现简单的ls命令
查看>>
Q:按F12进行网络安装系统时,一直无法进入,提示加载失败?
查看>>
我的友情链接
查看>>
解决AutoCAD acmgd.dll ARX命令中发现异常
查看>>
[转]passport.js学习笔记
查看>>
10.31T3 其他算法思想
查看>>
day10,11-Python 基本数据类型介绍之数字与字符串(看看就好)
查看>>
JAVA API----Math类和Random类
查看>>
求js数组中最小值
查看>>
UVA10018 Reverse and Add
查看>>
7.16学习进度
查看>>