日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

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

發布時間:2025/3/21 java 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java 中如何模拟真正的同时并发请求? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

有時需要測試一下某個功能的并發性能,又不要想借助于其他工具,索性就自己的開發語言,來一個并發請求就最方便了。

java中模擬并發請求,自然是很方便的,只要多開幾個線程,發起請求就好了。但是,這種請求,一般會存在啟動的先后順序了,算不得真正的同時并發!怎么樣才能做到真正的同時并發呢?是本文想說的點,java中提供了閉鎖 CountDownLatch, 剛好就用來做這種事就最合適了。

只需要:

  • 開啟n個線程,加一個閉鎖,開啟所有線程;

  • 待所有線程都準備好后,按下開啟按鈕,就可以真正的發起并發請求了。

  • package?com.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;public?class?LatchTest?{public?static?void?main(String[]?args)?throws?InterruptedException?{Runnable?taskTemp?=?new?Runnable()?{//?注意,此處是非線程安全的,留坑private?int?iCounter;@Overridepublic?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();//?設置連接方式:getconnection.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,當向遠程服務器傳送數據/寫數據時,需要設置為trueconnection.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-ee040be542c0connection.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;} }

    如上,就可以發起真正的并發請求了。

    并發請求操作流程示意圖如下:

    此處設置了一道門,以保證所有線程可以同時生效。但是,此處的同時啟動,也只是語言層面的東西,也并非絕對的同時并發。具體的調用還要依賴于CPU個數,線程數及操作系統的線程調度功能等,不過咱們也無需糾結于這些了,重點在于理解原理!

    與 CountDownLatch 有類似功能的,還有個工具柵欄 CyclicBarrier, 也是提供一個等待所有線程到達某一點后,再一起開始某個動作,效果一致,不過柵欄的目的確實比較純粹,就是等待所有線程到達,而前面說的閉鎖 CountDownLatch 雖然實現的也是所有線程到達后再開始,但是他的觸發點其實是 最后那一個開關,所以側重點是不一樣的。

    簡單看一下柵欄是如何實現真正同時并發呢?示例如下:

    //?與?閉鎖?結構一致 public?class?LatchTest?{public?static?void?main(String[]?args)?throws?InterruptedException?{Runnable?taskTemp?=?new?Runnable()?{private?int?iCounter;@Overridepublic?void?run()?{//?發起請求 //??????????????HttpClientOp.doGet("https://www.baidu.com/");iCounter++;System.out.println(System.nanoTime()?+?"?["?+?Thread.currentThread().getName()?+?"]?iCounter?=?"?+?iCounter);}};LatchTest?latchTest?=?new?LatchTest(); //????????latchTest.startTaskAllInOnce(5,?taskTemp);latchTest.startNThreadsByBarrier(5,?taskTemp);}public?void?startNThreadsByBarrier(int?threadNums,?Runnable?finishTask)?throws?InterruptedException?{//?設置柵欄解除時的動作,比如初始化某些值CyclicBarrier?barrier?=?new?CyclicBarrier(threadNums,?finishTask);//?啟動?n?個線程,與柵欄閥值一致,即當線程準備數達到要求時,柵欄剛好開啟,從而達到統一控制效果for?(int?i?=?0;?i?<?threadNums;?i++)?{Thread.sleep(100);new?Thread(new?CounterTask(barrier)).start();}System.out.println(Thread.currentThread().getName()?+?"?out?over...");} }class?CounterTask?implements?Runnable?{//?傳入柵欄,一般考慮更優雅方式private?CyclicBarrier?barrier;public?CounterTask(final?CyclicBarrier?barrier)?{this.barrier?=?barrier;}public?void?run()?{System.out.println(Thread.currentThread().getName()?+?"?-?"?+?System.currentTimeMillis()?+?"?is?ready...");try?{//?設置柵欄,使在此等待,到達位置的線程達到要求即可開啟大門barrier.await();}?catch?(InterruptedException?e)?{e.printStackTrace();}?catch?(BrokenBarrierException?e)?{e.printStackTrace();}System.out.println(Thread.currentThread().getName()?+?"?-?"?+?System.currentTimeMillis()?+?"?started...");} }

    其運行結果如下圖:

    各有其應用場景吧,關鍵在于需求。就本文示例的需求來說,個人更愿意用閉鎖一點,因為更可控了。但是代碼卻是多了,所以看你喜歡吧!

    總結

    以上是生活随笔為你收集整理的Java 中如何模拟真正的同时并发请求?的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。