有時(shí)候要測(cè)試一下某個(gè)功能的并發(fā)能力,又不要想借助于其他測(cè)試工具瓮下,索性就自己寫(xiě)簡(jiǎn)單的demo模擬一個(gè)并發(fā)請(qǐng)求就最方便了。如果熟悉jemter的測(cè)試某接口的并發(fā)能力其實(shí)更專業(yè),此處只是自己折騰著玩。
CountDownLatch和CyclicBarrier是jdk concurrent包下非常有用的兩個(gè)并發(fā)工具類荠商,它們提供了一種控制并發(fā)流程的手段皆撩。其實(shí)查看源碼它們都是在內(nèi)部維護(hù)了一個(gè)計(jì)數(shù)器控制流程的
CountDownLatch:一個(gè)或者多個(gè)線程溃列,等待其他多個(gè)線程完成某件事情之后才能執(zhí)行趾浅;
CyclicBarrier:多個(gè)線程互相等待胁编,直到到達(dá)同一個(gè)同步點(diǎn)酷鸦,再繼續(xù)一起執(zhí)行。
CountDownLatch和CyclicBarrier的區(qū)別
CountDownLatch的計(jì)數(shù)器滥比,線程完成一個(gè)記錄一個(gè)亚脆,計(jì)數(shù)器是遞減??計(jì)數(shù)器,只能使用一次
CyclicBarrier的計(jì)數(shù)器 更像是一個(gè)閥門(mén)盲泛,需要所有線程都到達(dá)濒持,閥門(mén)才能打開(kāi),然后繼續(xù)執(zhí)行查乒,計(jì)數(shù)器是遞增??計(jì)數(shù)器提供reset功能弥喉,可以多次使用
另外Semaphore可以控同時(shí)訪問(wèn)的線程個(gè)數(shù),通過(guò) acquire() 獲取一個(gè)許可玛迄,如果沒(méi)有就等待由境,而 release() 釋放一個(gè)許可。
通常我們模擬并發(fā)請(qǐng)求蓖议,一般都是多開(kāi)幾個(gè)線程虏杰,發(fā)起請(qǐng)求就好了。但是方式勒虾,一般會(huì)存在啟動(dòng)的先后順序了纺阔,算不得真正的同時(shí)并發(fā)!怎么樣才能做到真正的同時(shí)并發(fā)呢修然?是本文想說(shuō)的點(diǎn)笛钝,java中提供了閉鎖 CountDownLatch, CyclicBarrier 剛好就用來(lái)做這種事就最合適了质况。
下面分別使用CountDownLatch和CyclicBarrier來(lái)模擬并發(fā)的請(qǐng)求
CountDownLatch模擬
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; @Override public void run() { for(int i = 0; i < 10; i++) { // 發(fā)起請(qǐng)求 // 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 { // 使線程在此等待结榄,當(dāng)開(kāi)始門(mén)打開(kāi)時(shí),一起涌入門(mén)中 startGate.await(); try { task.run(); } finally { // 將結(jié)束門(mén)減1囤捻,減到0時(shí)臼朗,就可以開(kāi)啟結(jié)束門(mén)了 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..."); // 因開(kāi)啟門(mén)只需一個(gè)開(kāi)關(guān),所以立馬就開(kāi)啟開(kāi)始門(mén) startGate.countDown(); // 等等結(jié)束門(mén)開(kāi)啟 endGate.await(); long endTime = System.nanoTime(); System.out.println(endTime + " [" + Thread.currentThread() + "] All thread is completed."); return endTime - startTime; } }
執(zhí)行結(jié)果
CyclicBarrier模擬
// 與 閉鎖 結(jié)構(gòu)一致 public class LatchTest { public static void main(String[] args) throws InterruptedException { Runnable taskTemp = new Runnable() { private int iCounter; @Override public void run() { // 發(fā)起請(qǐng)求 // 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 { // 設(shè)置柵欄解除時(shí)的動(dòng)作蝎土,比如初始化某些值 CyclicBarrier barrier = new CyclicBarrier(threadNums, finishTask); // 啟動(dòng) n 個(gè)線程视哑,與柵欄閥值一致,即當(dāng)線程準(zhǔn)備數(shù)達(dá)到要求時(shí)誊涯,柵欄剛好開(kāi)啟挡毅,從而達(dá)到統(tǒng)一控制效果 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 { // 傳入柵欄,一般考慮更優(yōu)雅方式 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 { // 設(shè)置柵欄醋拧,使在此等待慷嗜,到達(dá)位置的線程達(dá)到要求即可開(kāi)啟大門(mén) barrier.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + " - " + System.currentTimeMillis() + " started..."); } }
執(zhí)行結(jié)果
并發(fā)請(qǐng)求操作流程示意圖如下:
此處設(shè)置了一道門(mén)淀弹,以保證所有線程可以同時(shí)生效丹壕。但是,此處的同時(shí)啟動(dòng)薇溃,也只是語(yǔ)言層面的東西菌赖,也并非絕對(duì)的同時(shí)并發(fā)。具體的調(diào)用還要依賴于CPU個(gè)數(shù)沐序,線程數(shù)及操作系統(tǒng)的線程調(diào)度功能等琉用,不過(guò)咱們也無(wú)需糾結(jié)于這些了,重點(diǎn)在于理解原理策幼!
畢竟測(cè)試并發(fā) 還得用專業(yè)的工具 jmeter 還是很方便的.
在這里給大家提供一個(gè)學(xué)習(xí)交流的平臺(tái)邑时,Java技術(shù)交流┟?810309655
具有1-5工作經(jīng)驗(yàn)的,面對(duì)目前流行的技術(shù)不知從何下手特姐,需要突破技術(shù)瓶頸的可以加群晶丘。
在公司待久了,過(guò)得很安逸唐含,但跳槽時(shí)面試碰壁浅浮。需要在短時(shí)間內(nèi)進(jìn)修、跳槽拿高薪的可以加群捷枯。
如果沒(méi)有工作經(jīng)驗(yàn)滚秩,但基礎(chǔ)非常扎實(shí),對(duì)java工作機(jī)制淮捆,常用設(shè)計(jì)思想郁油,常用java開(kāi)發(fā)框架掌握熟練的可以加群本股。
________________________________________________________________________________________________
加Java架構(gòu)師進(jìn)階交流群獲取Java工程化、高性能及分布式桐腌、高性能痊末、深入淺出。高架構(gòu)哩掺。
性能調(diào)優(yōu)凿叠、Spring,MyBatis嚼吞,Netty源碼分析和大數(shù)據(jù)等多個(gè)知識(shí)點(diǎn)高級(jí)進(jìn)階干貨的直播免費(fèi)學(xué)習(xí)權(quán)限
都是大牛帶飛?讓你少走很多的彎路的?群號(hào)是:?810309655對(duì)了?小白勿進(jìn)?最好是有開(kāi)發(fā)經(jīng)驗(yàn)
注:加群要求
1盒件、具有工作經(jīng)驗(yàn)的,面對(duì)目前流行的技術(shù)不知從何下手舱禽,需要突破技術(shù)瓶頸的可以加炒刁。
2、在公司待久了誊稚,過(guò)得很安逸翔始,但跳槽時(shí)面試碰壁。需要在短時(shí)間內(nèi)進(jìn)修里伯、跳槽拿高薪的可以加城瞎。
3、如果沒(méi)有工作經(jīng)驗(yàn)疾瓮,但基礎(chǔ)非常扎實(shí)脖镀,對(duì)java工作機(jī)制,常用設(shè)計(jì)思想狼电,常用java開(kāi)發(fā)框架掌握熟練的蜒灰,可以加。
4肩碟、覺(jué)得自己很牛B强窖,一般需求都能搞定。但是所學(xué)的知識(shí)點(diǎn)沒(méi)有系統(tǒng)化削祈,很難在技術(shù)領(lǐng)域繼續(xù)突破的可以加翅溺。
5.阿里Java高級(jí)大牛直播講解知識(shí)點(diǎn),分享知識(shí)岩瘦,多年工作經(jīng)驗(yàn)的梳理和總結(jié)未巫,帶著大家全面、科學(xué)地建立自己的技術(shù)體系和技術(shù)認(rèn)知启昧!