有时需要测试一下某个功能的并发性能,又不要想借助于其他工具,索性就自己的开发语言,来一个并发请求就最方便了。

java中模拟并发请求,自然是很方便的,只要多开几个线程,发起请求就好了。但是,这种请求,一般会存在启动的先后顺序了,算不得真正的同时并发!怎么样才能做到真正的同时并发呢?是本文想说的点,java中提供了闭锁 CountDownLatch, 刚好就用来做这种事就最合适了。

只需要:

开启n个线程,加一个闭锁,开启所有线程;

待所有线程都准备好后,按下开启按钮,就可以真正的发起并发请求了。

LatchTest.java

package com.gp.user;

import com.gp.user.utils.HttpUtils;

import java.util.concurrent.CountDownLatch;

import java.util.concurrent.TimeUnit;

/**

* @Author: GP3

* @Description: 并发请求测试

* @Date: Created in 10:16 2020/4/17

* @Modified By:

*/

public class LatchTest {

private static final int NUM = 1000; //并发数

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++) {

// 发起请求

HttpUtils.sendPost("http://172.16.7.206:8085/a/actApi/integrationTodoList",

"userName=gaopeng&pageNum=1&pageSize=15");

iCounter++;

System.out.println(System.nanoTime() + " [" + Thread.currentThread().getName() + "] iCounter = " + iCounter);

try {

Thread.sleep(5);

} catch (InterruptedException e) {

e.printStackTrace();

}

// }

}

};

LatchTest latchTest = new LatchTest();

latchTest.startTaskAllInOnce(NUM, 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.");

System.err.println("=====执行时间:" + TimeUnit.NANOSECONDS.toMillis(endTime - startTime) + "豪秒");

return endTime - startTime;

}

}

复制代码

HttpUtils.java

package com.gp.user.utils;

import java.io.*;

import java.net.URL;

import java.net.URLConnection;

import java.util.Iterator;

import java.util.Map;

/**

* @Author: GP3

* @Description: http请求

* @Date: Created in 10:10 2020/4/17

* @Modified By:

*/

public class HttpUtils {

public HttpUtils() {

}

/**

* 向指定URL发送POST请求

* @param url

* @param paramMap

* @return 响应结果

*/

public static String sendPost(String url, Map paramMap) {

PrintWriter out = null;

BufferedReader in = null;

String result = "";

try {

URL realUrl = new URL(url);

// 打开和URL之间的连接

URLConnection conn = realUrl.openConnection();

// 设置通用的请求属性

conn.setRequestProperty("accept", "*/*");

conn.setRequestProperty("connection", "Keep-Alive");

conn.setRequestProperty("user-agent","Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");

// conn.setRequestProperty("Charset", "UTF-8");

// 发送POST请求必须设置如下两行

conn.setDoOutput(true);

conn.setDoInput(true);

// 获取URLConnection对象对应的输出流

out = new PrintWriter(conn.getOutputStream());

// 设置请求属性

String param = "";

if (paramMap != null && paramMap.size() > 0) {

Iterator ite = paramMap.keySet().iterator();

while (ite.hasNext()) {

String key = ite.next();// key

String value = paramMap.get(key);

param += key + "=" + value + "&";

}

param = param.substring(0, param.length() - 1);

}

// 发送请求参数

out.print(param);

// flush输出流的缓冲

out.flush();

// 定义BufferedReader输入流来读取URL的响应

in = new BufferedReader(

new InputStreamReader(conn.getInputStream()));

String line;

while ((line = in.readLine()) != null) {

result += line;

}

} catch (Exception e) {

System.err.println("发送 POST 请求出现异常!" + e);

e.printStackTrace();

}

// 使用finally块来关闭输出流、输入流

finally {

try {

if (out != null) {

out.close();

}

if (in != null) {

in.close();

}

} catch (IOException ex) {

ex.printStackTrace();

}

}

return result;

}

/**

* 向指定 URL 发送POST方法的请求

*

* @param url

* 发送请求的 URL

* @param param

* 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。

* @return 所代表远程资源的响应结果

*/

public static String sendPost(String url, String param) {

PrintWriter out = null;

BufferedReader in = null;

String result = "";

try {

URL realUrl = new URL(url);

// 打开和URL之间的连接

URLConnection conn = realUrl.openConnection();

// 设置通用的请求属性

// conn.setRequestProperty("Accept", "application/json"); // 设置接收数据的格式

// conn.setRequestProperty("Content-Type", "application/json");

conn.setRequestProperty("accept", "*/*");

// conn.setRequestProperty("connection", "Keep-Alive");

// conn.setRequestProperty("user-agent","Mozilla/4.0 (compatible; MSIE 6.0;

// Windows NT 5.1;SV1)");

// 发送POST请求必须设置如下两行

conn.setDoOutput(true);

conn.setDoInput(true);

// 获取URLConnection对象对应的输出流

out = new PrintWriter(conn.getOutputStream());

// 发送请求参数

out.print(param);

// flush输出流的缓冲

out.flush();

// 定义BufferedReader输入流来读取URL的响应

in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));

String line;

while ((line = in.readLine()) != null) {

result += line;

}

} catch (Exception e) {

System.out.println("发送 POST 请求出现异常!" + e);

e.printStackTrace();

}

// 使用finally块来关闭输出流、输入流

finally {

try {

if (out != null) {

out.close();

}

if (in != null) {

in.close();

}

} catch (IOException ex) {

ex.printStackTrace();

}

}

return result;

}

}

复制代码

执行结果如下:

如上,就可以发起真正的并发请求了。

并发请求操作流程示意图如下:

此处设置了一道门,以保证所有线程可以同时生效。但是,此处的同时启动,也只是语言层面的东西,也并非绝对的同时并发。具体的调用还要依赖于CPU个数,线程数及操作系统的线程调度功能等,不过我们也无需纠结于这些了,重点在于理解原理!

java 模拟多线程并发_Java中模拟同时并发请求相关推荐

  1. java实现多线程抢单_Java模拟多线程实现抢票代码实例

    这篇文章主要介绍了Java模拟多线程实现抢票,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 实现100张票抢购的demo 这里需要一个变量,来保存1 ...

  2. java 共享锁 独占锁_java中的公平锁、非公平锁、可重入锁、递归锁、自旋锁、独占锁和共享锁...

    一.公平锁与非公平锁 1.1 概述 公平锁:是指多个线程按照申请锁的顺序来获取锁. 非公平锁:是指在多线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的线程比先申请的线程优先获取到锁,在高并发的情 ...

  3. java可以多重继承吗_Java中的多重继承与组合vs继承

    java可以多重继承吗 有时我写了几篇有关Java继承,接口和组成的文章. 在这篇文章中,我们将研究多重继承,然后了解组成优于继承的好处. Java中的多重继承 多重继承是创建具有多个超类的单个类的能 ...

  4. java有什么字符串_Java 中操作字符串都有哪些类?它们之间有什么区别

    1. String.StringBuffer.StringBuilder 原文出自<编写高质量代码:改善 Java 程序的 151 个建议> CharSequence 接口有三个实现类与字 ...

  5. java 链接重排序_JAVA中JVM的重排序详细介绍

    重排序通常是编译器或运行时环境为了优化程序性能而采取的对指令进行重新排序执行的一种手段.重排序分为两类:编译期重排序和运行期重排序,分别对应编译时和运行时环境 在并发程序中,程序员会特别关注不同进程或 ...

  6. java 如何结束线程_java中,如何安全的结束一个正在运行的线程?

    问题 Java中提供了很多调度线程的方法,上一节介绍了其中一种控制线程的方法:如何等待一个线程结束.那么如果不希望等待线程结束,而是根据问题的需要随时都要中断线程使其结束,这种对线程的控制方法该如何实 ...

  7. java 什么是哨兵_Java中使用redis哨兵模式

    Redis概述 在传统的软件项目中,使用数据库进行数据存储,但是有一些致命的缺陷,这些缺陷反映在性能方面.由于数据库存储数据的介质是磁盘,而磁盘读写的速度比较慢.在不存在大量高并发的应用场景中,这个缺 ...

  8. java中有没有栈_Java中堆和栈有什么区别

    stack 和 heep 都是内存的一部分stack 空间小,速度比较快, 用来放对象的引用heep 大,一般所有创建的对象都放在这里.栈(stack):是一个先进后出的数据结构,通常用于保存方法(函 ...

  9. java单例代码_java中的单例模式的代码怎么写

    单例模式在我们日常的项目中十分常见,当我们在项目中需要一个这样的一个对象,这个对象在内存中只能有一个实例,这时我们就需要用到单例. 一般说来,单例模式通常有以下几种: 1.饥汉式单例 public c ...

最新文章

  1. 五分钟没有操作自动退出_这又是什么骚操作??5只蚂蚁战略配售基金拟增设B类份额,自动赎回退出!!...
  2. 这是给程序员专用的书吗?
  3. hdoj5317【素数预处理】
  4. ServletContextListener
  5. 2048(lj模拟)
  6. java-01 JAVA三大版本比较JDK、JRE、JVM 的关系
  7. 图像卷积与滤波知识点整理(2)
  8. 【渝粤题库】国家开放大学2021春1020国际私法题目
  9. Android Runnable与Handler和Thread的使用,Handler构造方法弱引用实现
  10. 生成新的dataframe_Python之Pandas使用系列(九):DataFrame中列操作的技巧
  11. IDAutomation的条形码字体和工具集TrueType Font Package
  12. com.android.yf.idp,QQ轻聊版-com.tencent.qqlite_v3.3.0_apkpure.apk
  13. HT513 I2S输入2.8W单声道D类音频功放IC
  14. 一些简单的局域网入侵命令
  15. C++多态的职工管理系统
  16. 计算机如何执行一条机器指令
  17. 很好的励志文章(特别针对刚刚进入职场的毕业生而写)
  18. Windows server 2019 安装VPN
  19. Maven的几个常用Plugin
  20. 拉里•埃里森和他的Oracle公司

热门文章

  1. java jvm优化(一)
  2. 【笔记本装内存】谢谢师兄帮我装内存条!!
  3. 从永远到永远-电吉他综合效果器
  4. 直播预告 11.18 | KDD-7,纽约大学斯特恩商学院、伊利诺伊大学香槟分校 PhD
  5. Html5 APP 多语言切换
  6. 怎么做一次用心的PPT演讲
  7. 安卓手机管理_这个软件竟然能彻底解决安卓手机通知管理难题!
  8. 使用anaconda安装pytorch——看这一篇就行了
  9. 华为删除dhcp地址池_干货|什么是DHCP?这些我们应该知道
  10. 2W10-ASEMI整流圆桥2W10