java学习基地

微信扫一扫 分享朋友圈

已有 1262 人浏览分享

Java中如何模拟真正的同时并发请求?

[复制链接]
1262 0
本帖最初由 渭耶java 于 2021-3-20 14:20 编纂

偶然需求测试一下某个功用的并收机能,又没有要念借助于其他东西,干脆便本人的开辟言语,去一个并收恳求便最便利了。

java中模仿并收恳求,天然是很便利的,只需多开寂线程,倡议恳求就行了。可是,这类恳求,普通会存正在启动当比后挨次了,算没有得真实的同时并收!怎样才气做到真实的同时并收呢?是本伪彪道的面,java中供给了闭锁 CountDownLatch, 恰好便雍么做这类事便最适宜了。

只需求:

  • 开启n个线程,减一个闭锁,开启一切线程;

  • 待一切线程皆筹办好后,按下开启按钮,就能够真实的倡议并收恳求了。

    1. package com.test;  
    2.   
    3. import java.io.BufferedReader;  
    4. import java.io.IOException;  
    5. import java.io.InputStream;  
    6. import java.io.InputStreamReader;  
    7. import java.io.OutputStream;  
    8. import java.net.HttpURLConnection;  
    9. import java.net.MalformedURLException;  
    10. import java.net.URL;  
    11. import java.util.concurrent.CountDownLatch;  
    12.   
    13. public class LatchTest {  
    14.   
    15.     public static void main(String[] args) throws InterruptedException {  
    16.         Runnable taskTemp = new Runnable() {  
    17.   
    18.        // 留意,此处长短线程宁静的,留坑  
    19.             private int iCounter;  
    20.   
    21.             @Override  
    22.             public void run() {  
    23.                 for(int i = 0; i < 10; i++) {  
    24.                     // 倡议恳求  
    25. //                    HttpClientOp.doGet("https://www.百度.com/");  
    26.                     iCounter++;  
    27.                     System.out.println(System.nanoTime() + " [" + Thread.currentThread().getName() + "] iCounter = " + iCounter);  
    28.                     try {  
    29.                         Thread.sleep(100);  
    30.                     } catch (InterruptedException e) {  
    31.                         e.printStackTrace();  
    32.                     }  
    33.                 }  
    34.             }  
    35.         };  
    36.   
    37.         LatchTest latchTest = new LatchTest();  
    38.         latchTest.startTaskAllInOnce(5, taskTemp);  
    39.     }  
    40.   
    41.     public long startTaskAllInOnce(int threadNums, final Runnable task) throws InterruptedException {  
    42.         final CountDownLatch startGate = new CountDownLatch(1);  
    43.         final CountDownLatch endGate = new CountDownLatch(threadNums);  
    44.         for(int i = 0; i < threadNums; i++) {  
    45.             Thread t = new Thread() {  
    46.                 public void run() {  
    47.                     try {  
    48.                         // 使线程正在吹廊待,当开端门翻开时,一同涌进梅市  
    49.                         startGate.await();  
    50.                         try {  
    51.                             task.run();  
    52.                         } finally {  
    53.                             // 将完毕闷骢1,加到0时,就能够开启完毕门了  
    54.                             endGate.countDown();  
    55.                         }  
    56.                     } catch (InterruptedException ie) {  
    57.                         ie.printStackTrace();  
    58.                     }  
    59.                 }  
    60.             };  
    61.             t.start();  
    62.         }  
    63.         long startTime = System.nanoTime();  
    64.         System.out.println(startTime + " [" + Thread.currentThread() + "] All thread is ready, concurrent going...");  
    65.         // 果开启梅驶需一个开闭,以是坐马便开启开端门  
    66.         startGate.countDown();  
    67.         // 等等完毕门开启  
    68.         endGate.await();  
    69.         long endTime = System.nanoTime();  
    70.         System.out.println(endTime + " [" + Thread.currentThread() + "] All thread is completed.");  
    71.         return endTime - startTime;  
    72.     }  
    73. }  
    赶钙代码
    其施行结果以下图所示:                                                                                                                                                                                                                                                                                                                                          httpClientOp 东西类,可使用 成生的东西包,也能够本人写一个扼要的会见办法,参考以下:
    1. class HttpClientOp {  
    2.     public static String doGet(String httpurl) {  
    3.         HttpURLConnection connection = null;  
    4.         InputStream is = null;  
    5.         BufferedReader br = null;  
    6.         String result = null;// 返回成果字符串  
    7.         try {  
    8.             // 创立长途url毗连工具  
    9.             URL url = new URL(httpurl);  
    10.             // 经由过程长途url毗连工具翻开一个毗连,强转成httpURLConnection类  
    11.             connection = (HttpURLConnection) url.openConnection();  
    12.             // 设置毗连方法:get  
    13.             connection.setRequestMethod("GET");  
    14.             // 设置毗连主机效劳器的超不时间:15000毫秒  
    15.             connection.setConnectTimeout(15000);  
    16.             // 设置读与长途返回的数据工夫:60000毫秒  
    17.             connection.setReadTimeout(60000);  
    18.             // 收收恳求  
    19.             connection.connect();  
    20.             // 经由过程connection毗连,获得输进流  
    21.             if (connection.getResponseCode() == 200) {  
    22.                 is = connection.getInputStream();  
    23.                 // 启拆输进流is,并指定字符散  
    24.                 br = new BufferedReader(new InputStreamReader(is, "UTF-8"));  
    25.                 // 寄存数据  
    26.                 StringBuffer sbf = new StringBuffer();  
    27.                 String temp = null;  
    28.                 while ((temp = br.readLine()) != null) {  
    29.                     sbf.append(temp);  
    30.                     sbf.append("\r\n");  
    31.                 }  
    32.                 result = sbf.toString();  
    33.             }  
    34.         } catch (MalformedURLException e) {  
    35.             e.printStackTrace();  
    36.         } catch (IOException e) {  
    37.             e.printStackTrace();  
    38.         } finally {  
    39.             // 封闭资本  
    40.             if (null != br) {  
    41.                 try {  
    42.                     br.close();  
    43.                 } catch (IOException e) {  
    44.                     e.printStackTrace();  
    45.                 }  
    46.             }  
    47.   
    48.             if (null != is) {  
    49.                 try {  
    50.                     is.close();  
    51.                 } catch (IOException e) {  
    52.                     e.printStackTrace();  
    53.                 }  
    54.             }  
    55.   
    56.             connection.disconnect();// 封闭长途毗连  
    57.         }  
    58.   
    59.         return result;  
    60.     }  
    61.   
    62.     public static String doPost(String httpUrl, String param) {  
    63.   
    64.         HttpURLConnection connection = null;  
    65.         InputStream is = null;  
    66.         OutputStream os = null;  
    67.         BufferedReader br = null;  
    68.         String result = null;  
    69.         try {  
    70.             URL url = new URL(httpUrl);  
    71.             // 经由过程长途url毗连工具翻开毗连  
    72.             connection = (HttpURLConnection) url.openConnection();  
    73.             // 设置毗连恳求方法  
    74.             connection.setRequestMethod("POST");  
    75.             // 设置毗连主机效劳器超不时间:15000毫秒  
    76.             connection.setConnectTimeout(15000);  
    77.             // 设置读与主机效劳器返回数据超不时间:60000毫秒  
    78.             connection.setReadTimeout(60000);  
    79.   
    80.             // 默许值为:false,当背长途效劳器传收数据/写数据时,需求设置为true  
    81.             connection.setDoOutput(true);  
    82.             // 默许值为:true,当前背长途效劳读与数据时,设置为true,该参数无足轻重  
    83.             connection.setDoInput(true);  
    84.             // 设置传进参数的格局:恳求参数该当是 name1=value1&name2=value2 的情势。  
    85.             connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");  
    86.             // 设置鉴权疑息:Authorization: Bearer da3efcbf-0845-4fe3-8aba-ee040be542c0  
    87.             connection.setRequestProperty("Authorization", "Bearer da3efcbf-0845-4fe3-8aba-ee040be542c0");  
    88.             // 经由过程毗连工具获得一个输出流  
    89.             os = connection.getOutputStream();  
    90.             // 经由过程输出流工具将参数写进来/传输进来,它是经由过程字节数组写出的  
    91.             os.write(param.getBytes());  
    92.             // 经由过程毗连工具获得一个输进流,背长途读与  
    93.             if (connection.getResponseCode() == 200) {  
    94.   
    95.                 is = connection.getInputStream();  
    96.                 // 对输进流工具停止包拆:charset按照事情项目组的请求去设置  
    97.                 br = new BufferedReader(new InputStreamReader(is, "UTF-8"));  
    98.   
    99.                 StringBuffer sbf = new StringBuffer();  
    100.                 String temp = null;  
    101.                 // 轮回遍历一止一止读与数据  
    102.                 while ((temp = br.readLine()) != null) {  
    103.                     sbf.append(temp);  
    104.                     sbf.append("\r\n");  
    105.                 }  
    106.                 result = sbf.toString();  
    107.             }  
    108.         } catch (MalformedURLException e) {  
    109.             e.printStackTrace();  
    110.         } catch (IOException e) {  
    111.             e.printStackTrace();  
    112.         } finally {  
    113.             // 封闭资本  
    114.             if (null != br) {  
    115.                 try {  
    116.                     br.close();  
    117.                 } catch (IOException e) {  
    118.                     e.printStackTrace();  
    119.                 }  
    120.             }  
    121.             if (null != os) {  
    122.                 try {  
    123.                     os.close();  
    124.                 } catch (IOException e) {  
    125.                     e.printStackTrace();  
    126.                 }  
    127.             }  
    128.             if (null != is) {  
    129.                 try {  
    130.                     is.close();  
    131.                 } catch (IOException e) {  
    132.                     e.printStackTrace();  
    133.                 }  
    134.             }  
    135.             // 断开取长途地点url的毗连  
    136.             connection.disconnect();  
    137.         }  
    138.         return result;  
    139.     }  
    140. }  
    赶钙代码

    如上,就能够倡议真实的并收恳求了。

    并收恳求操纵流程表示图以下:                                                                                                                                                                                                                                                                                                                  此处设置了一讲门,以包管一切线潮以同时见效。可是,此处的同时启动,也执偾言语层里的工具,也并不是尽对的同时并收。详细的挪用借要依靠于CPU个数,线程数及操纵体系当边程调理功用等,不外我们也无需纠结于那些了,重面正在于了解道理!取 CountDownLatch 有相似功用的,另有个东西栅栏 CyclicBarrier, 也是供给一个等候一切线程抵达某一面后,再一同开端某个行动,结果分歧,不外栅栏的目标的确比力地道,便是等候一切线程抵达,而前里道的闭锁 CountDownLatch 固然完成的也是一切线程抵达后再开端,可是他的触收面实际上是 最初那一个开闭,以是偏重面是纷歧样的。

    简朴看一下栅揽嗲怎样完成实正同时并收呢?示比方下:

    1. // 取 闭锁 构造分歧  
    2. public class LatchTest {  
    3.   
    4.     public static void main(String[] args) throws InterruptedException {  
    5.   
    6.         Runnable taskTemp = new Runnable() {  
    7.   
    8.             private int iCounter;  
    9.   
    10.             @Override  
    11.             public void run() {  
    12.                 // 倡议恳求  
    13. //              HttpClientOp.doGet("https://www.百度.com/");  
    14.                 iCounter++;  
    15.                 System.out.println(System.nanoTime() + " [" + Thread.currentThread().getName() + "] iCounter = " + iCounter);  
    16.             }  
    17.         };  
    18.   
    19.         LatchTest latchTest = new LatchTest();  
    20. //        latchTest.startTaskAllInOnce(5, taskTemp);  
    21.         latchTest.startNThreadsByBarrier(5, taskTemp);  
    22.     }  
    23.   
    24.     public void startNThreadsByBarrier(int threadNums, Runnable finishTask) throws InterruptedException {  
    25.         // 设置栅栏消除时的行动,好比初初化钠舂值  
    26.         CyclicBarrier barrier = new CyclicBarrier(threadNums, finishTask);  
    27.         // 启动 n 个线程,取栅栏阀值分歧,即当线程筹办数到达请求时,栅琅好开启,从而到达同一掌握结果  
    28.         for (int i = 0; i < threadNums; i++) {  
    29.             Thread.sleep(100);  
    30.             new Thread(new CounterTask(barrier)).start();  
    31.         }  
    32.         System.out.println(Thread.currentThread().getName() + " out over...");  
    33.     }  
    34. }  
    35.   
    36.   
    37. class CounterTask implements Runnable {  
    38.   
    39.     // 传进栅阑霈普通思索更文雅方法  
    40.     private CyclicBarrier barrier;  
    41.   
    42.     public CounterTask(final CyclicBarrier barrier) {  
    43.         this.barrier = barrier;  
    44.     }  
    45.   
    46.     public void run() {  
    47.         System.out.println(Thread.currentThread().getName() + " - " + System.currentTimeMillis() + " is ready...");  
    48.         try {  
    49.             // 设置栅阑霈使正在吹廊待,抵达地位当边程到达请求便可开启年夜门  
    50.             barrier.await();  
    51.         } catch (InterruptedException e) {  
    52.             e.printStackTrace();  
    53.         } catch (BrokenBarrierException e) {  
    54.             e.printStackTrace();  
    55.         }  
    56.         System.out.println(Thread.currentThread().getName() + " - " + System.currentTimeMillis() + " started...");  
    57.     }  
    58. }  
    赶钙代码
    其运转成果以下图:                                                                                                                                                                                   

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x

举报 使用道具

回复
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

0

关注

1

粉丝

308

主题
精彩推荐
热门资讯
网友晒图
图文推荐

Archiver|手机版|java学习基地 |网站地图

GMT+8, 2021-4-14 12:41 , Processed in 0.472675 second(s), 32 queries .

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.