一個瞬間高并發壓測程序的研究

這兩個要搞一個萬級接入量的算法功能壓測程序,查了一下網上的相關資料。測試方案主要參考了下面這篇文章,但是實現和測試方式不同。

reference:http://blog.csdn.net/zhao9tian/article/details/40346899

(之前已經對多線程的相關概念和工程上實際應用需要注意的地方有所了解。但是真正搞這個壓測過程中還是出了很多問題。建議先要搞清并發和并行,內存可見性和線程安全性,synchronized的使用方式和鎖的概念)

要求:模擬200個設備,盡量瞬間并發量達到200。

思路

第一種:線程池模擬200個線程——wait等待線程數達200——notifyAll喚醒所有線程

第二種:線程池模擬200個線程——阻塞線程——達到200條件釋放

比較

兩種方案都可以實現瞬時高并發的模擬,但是建議使用第二種方案。

第一種方案中,壓測過程中,wait狀態下的線程已經釋放對象上的鎖定,喚醒時會極大的消耗CPU資源。壓測程序可能直接導致機器崩潰

第二種方案,由于阻塞過程中,線程不會釋放掉目前持有的對象資源,因此等待條件釋放不會造成資源的過度消耗。

但是應當選擇好阻塞方式,避免線程操作時的死鎖。同時實現線程之間的通信。

wait-notifyAll

代碼較簡單,通過線程池啟動1000個線程,通過synchronized保證線程可見性,和安全性。

當線程數量未達到1000時,wait使線程退出CPU,釋放鎖。

當線程數量達到1000時,notifyAll通知等待集上的線程,喚醒線程。

代碼如下:

/**

* @author:???? irvingyuan

* @since?????? 2017年1月22日 下午4:51:51

* @version:

*/

public class Parallellimit {

public static void main(String[] args) {

ExecutorService pool = Executors.newCachedThreadPool();

Counts count = new Counts(); ?//共享操作該計數變量,不能使用int或者integer,Java無法對非對象、和包裝類進行加鎖wait

count.num = 0;

for(int i=0;i<10000;i++){ ? ? //啟動線程

MyRunnable runnable = new MyRunnable(count);

pool.execute(runnable);

}

pool.shutdown(); ? ? //關閉線程池,無法加入新線程任務,但不影響現有線程

}

}

public class MyRunnable implements Runnable{

private Counts count ;

/**

* 通過構造方法傳入初值,避免set和get時線程的不安全性

*/

public MyRunnable(Counts count){

this.count = count;

}

public void run() {

try {

/**

* 加鎖,保證線程可見性和安全性

*/

synchronized (count) {

count.num++;

if(count.num<10000){

System.out.println(count.num);

count.wait();//一定要調用count對象的wait,默認對this,無法持有線程的鎖,拋出異常

}

/**

* 達到10000時喚醒所有線程

*/

if(count.num == 10000){

count.notifyAll();

}

System.out.println("并發量 count="+count.num);

}

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

測試結果

并發喚醒1000個線程時,CPU瞬時使用率瞬時增長17%左右。可見CPU負擔很大。

繼續增大線程數,JVM拋OOM異常退出,需要修改啟動參數

block阻塞方式

同步代碼塊持有count的鎖,保證創建出正確的線程數量。判斷不夠并發量時,使用while阻塞線程。

當達到并發量時,阻塞條件失效,線程繼續運行。

代碼如下:

/**

* 阻塞方式創建瞬時高并發

* @author:???? irvingyuan

* @since?????? 2017年1月23日 下午4:45:56

* @version:

*/

public class BlockRunnable implements Runnable{

private Counts count ;

/**

* 通過構造方法傳入初值,避免set和get時線程的不安全性

*/

public BlockRunnable(Counts count){

this.count = count;

}

public void run() {

/**

* this肯定失效,this調用處為runnable對象

* 此時加鎖表示多個線程只能有一個線程在某時刻操作該runnable

* new出來了n個線程,自己調用自己的,this必定失效

* synchronized (this) {

*/

synchronized (count) {

count.num++;

System.out.println("Thread count = "+count.num);

}

/**

* 注意synchronized的粒度

* while放在代碼快中會導致線程一直持有鎖等待,下一個線程無法生成和進行

*/

while(count.num<100);

//并發操作

System.out.println("concurrency count = "+count.num);

}

}

測試效果

100個線程瞬時的CPU使用率居然激增到了100%,和資料說的完全想法,更加損耗系統資源。(是不是因為while?)

//原文使用sleep,個人認為時間不好掌握,用while直接長時間做條件阻塞

CountDownLatch

Java提供的實現阻塞和釋放線程的類,嘗試是否符合推薦的規律。

其中主要包含三個方法

countDownLatch(100)?????類通過構造方法傳入計數數量。

countDown()?????方法會減少一個計數值

await()?????方法自動阻塞線程,直到count的值變為0

執行過程中,同步操作count后,開始等待,直到100個線程全部創建后并發執行

代碼如下

public class Parallellimit {

public static void main(String[] args) {

ExecutorService pool = Executors.newCachedThreadPool();

Counts count = new Counts();

count.num = 0;

CountDownLatch cdl = new CountDownLatch(100);

for(int i=0;i<100;i++){

CountRunnable runnable = new CountRunnable(cdl);

pool.execute(runnable);

}

}

}

/**

* 〈countDownlatch實現高并發〉

* @author:???? irvingyuan

* @since?????? 2017年1月23日 下午5:45:59

* @version:

*/

public class CountRunnable implements Runnable {

private CountDownLatch countDownLatch;

public CountRunnable(CountDownLatch countDownLatch){

this.countDownLatch = countDownLatch;

}

public void run() {

try {

/**

* 不加鎖也可以支持,雖然打印出的值不對,但最后計算次數卻是100次

* 說明確實是執行了整整100次才并發,計算次數正確

*/

synchronized (countDownLatch) {

/**

* 每次減少一個容量

*/

countDownLatch.countDown();

System.out.println("thread counts = "+(countDownLatch.getCount()));

}

/**

* 阻塞線程,直到countDown至0

*/

countDownLatch.await();

System.out.println("concurrency counts = "+(100-countDownLatch.getCount()));

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

測試結果

CPU增長率大約10%左右,相對于wait-notify方式要減少約一半。

綜上,阻塞似乎是最坑爹的一種方式

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,546評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,570評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,505評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,017評論 1 313
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,786評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,219評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,287評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,438評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,971評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,796評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,995評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,540評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,230評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,662評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,918評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,697評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,991評論 2 374

推薦閱讀更多精彩內容

  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法,內部類的語法,繼承相關的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,721評論 18 399
  • layout: posttitle: 《Java并發編程的藝術》筆記categories: Javaexcerpt...
    xiaogmail閱讀 5,849評論 1 19
  • 日堯林夕 鳴笛聲想起 火車緩緩滑動出站臺 我站在窗外看你 淚流滿面 前一秒 你我含情相擁 人潮的擁擠漸漸吹...
    子辛木夕閱讀 282評論 0 0
  • 剛種下去的青菜和生菜發芽啦! 綠色果然是最舒服的顏色, 保護視力又美麗。 以前不是特別喜歡吃生菜, 後來是別人炒了...
    蘇步閱讀 254評論 0 2
  • 李默默L閱讀 557評論 0 0