有时需要测试一下某个功能的并发性能, 又不要想借助于其他工具, 索性就自己的开发语言, 来一个并发请求就最方便了.
java 中模拟并发请求, 自然是很方便的, 只要多开几个线程, 发起请求就好了. 但是, 这种请求, 一般会存在线后顺序了. 怎么样才能做到真正的同时并发呢? 是本文想说的点, java 中提供了闭锁 CountDownLatch, 刚好就用来做这种事就最合适了.
只需要: 1. 开启 n 个线程, 加一个闭锁, 开启所有线程; 2. 待所有线程都准备好后, 按下开启按钮, 就可以真正的发起并发请求了.
- package com.yougewe.test;
- import java.io.BufferedReader;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.InputStreamReader;
- import java.io.OutputStream;
- import java.NET.HttpURLConnection;
- import java.NET.MalformedURLException;
- import java.NET.URL;
- import java.util.concurrent.CountDownLatch;
- /**
- * Created by weiyong on 2018/10/5.
- */
- public class LatchTest {
- public static void main(String[] args) throws InterruptedException {
- Runnable taskTemp = new Runnable() {
- private int iCounter;
- @Override
- public void run() {
- for(int i = 0; i < 10; i++) {
- // 发起请求
- // HttpClientOp.doGet("https://www.baidu.com/");
- iCounter++;
- System.out.println(System.nanoTime() + "[" + Thread.currentThread().getName() + "] iCounter =" + iCounter);
- try {
- Thread.sleep(100);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- };
- LatchTest latchTest = new LatchTest();
- latchTest.startTaskAllInOnce(5, taskTemp);
- }
- public long startTaskAllInOnce(int threadNums, final Runnable task) throws InterruptedException {
- final CountDownLatch startGate = new CountDownLatch(1);
- final CountDownLatch endGate = new CountDownLatch(threadNums);
- for(int i = 0; i < threadNums; i++) {
- Thread t = new Thread() {
- public void run() {
- try {
- // 使线程在此等待, 当开始门打开时, 一起涌入门中
- startGate.await();
- try {
- task.run();
- } finally {
- // 将结束门减 1, 减到 0 时, 就可以开启结束门了
- endGate.countDown();
- }
- } catch (InterruptedException IE) {
- IE.printStackTrace();
- }
- }
- };
- t.start();
- }
- long startTime = System.nanoTime();
- System.out.println(startTime + "[" + Thread.currentThread() + "] All thread is ready, concurrent going...");
- // 因开启门只需一个开关, 所以立马就开启开始门
- startGate.countDown();
- // 等等结束门开启
- endGate.await();
- long endTime = System.nanoTime();
- System.out.println(endTime + "[" + Thread.currentThread() + "] All thread is completed.");
- return endTime - startTime;
- }
- }
httpClientOp 工具类, 可以使用 成熟的工具包, 也可以自己写一个简要的访问方法, 参考如下:
- class HttpClientOp {
- public static String doGet(String httpurl) {
- HttpURLConnection connection = null;
- InputStream is = null;
- BufferedReader br = null;
- String result = null;// 返回结果字符串
- try {
- // 创建远程 url 连接对象
- URL url = new URL(httpurl);
- // 通过远程 url 连接对象打开一个连接, 强转成 httpURLConnection 类
- connection = (HttpURLConnection) url.openConnection();
- // 设置连接方式: get
- connection.setRequestMethod("GET");
- // 设置连接主机服务器的超时时间: 15000 毫秒
- connection.setConnectTimeout(15000);
- // 设置读取远程返回的数据时间: 60000 毫秒
- connection.setReadTimeout(60000);
- // 发送请求
- connection.connect();
- // 通过 connection 连接, 获取输入流
- if (connection.getResponseCode() == 200) {
- is = connection.getInputStream();
- // 封装输入流 is, 并指定字符集
- br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
- // 存放数据
- StringBuffer sbf = new StringBuffer();
- String temp = null;
- while ((temp = br.readLine()) != null) {
- sbf.append(temp);
- sbf.append("\r\n");
- }
- result = sbf.toString();
- }
- } catch (MalformedURLException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- } finally {
- // 关闭资源
- if (null != br) {
- try {
- br.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- if (null != is) {
- try {
- is.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- connection.disconnect();// 关闭远程连接
- }
- return result;
- }
- public static String doPost(String httpUrl, String param) {
- HttpURLConnection connection = null;
- InputStream is = null;
- OutputStream os = null;
- BufferedReader br = null;
- String result = null;
- try {
- URL url = new URL(httpUrl);
- // 通过远程 url 连接对象打开连接
- connection = (HttpURLConnection) url.openConnection();
- // 设置连接请求方式
- connection.setRequestMethod("POST");
- // 设置连接主机服务器超时时间: 15000 毫秒
- connection.setConnectTimeout(15000);
- // 设置读取主机服务器返回数据超时时间: 60000 毫秒
- connection.setReadTimeout(60000);
- // 默认值为: false, 当向远程服务器传送数据 / 写数据时, 需要设置为 true
- connection.setDoOutput(true);
- // 默认值为: true, 当前向远程服务读取数据时, 设置为 true, 该参数可有可无
- connection.setDoInput(true);
- // 设置传入参数的格式: 请求参数应该是 name1=value1&name2=value2 的形式.
- connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
- // 设置鉴权信息: Authorization: Bearer da3efcbf-0845-4fe3-8aba-ee040be542c0
- connection.setRequestProperty("Authorization", "Bearer da3efcbf-0845-4fe3-8aba-ee040be542c0");
- // 通过连接对象获取一个输出流
- os = connection.getOutputStream();
- // 通过输出流对象将参数写出去 / 传输出去, 它是通过字节数组写出的
- os.write(param.getBytes());
- // 通过连接对象获取一个输入流, 向远程读取
- if (connection.getResponseCode() == 200) {
- is = connection.getInputStream();
- // 对输入流对象进行包装: charset 根据工作项目组的要求来设置
- br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
- StringBuffer sbf = new StringBuffer();
- String temp = null;
- // 循环遍历一行一行读取数据
- while ((temp = br.readLine()) != null) {
- sbf.append(temp);
- sbf.append("\r\n");
- }
- result = sbf.toString();
- }
- } catch (MalformedURLException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- } finally {
- // 关闭资源
- if (null != br) {
- try {
- br.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- if (null != os) {
- try {
- os.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- if (null != is) {
- try {
- is.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- // 断开与远程地址 url 的连接
- connection.disconnect();
- }
- return result;
- }
- }
如上, 就可以发起真正的并发请求了.
来源: http://www.tuicool.com/articles/iqEfE3N