一个瞬间高并发压测程序的研究

这两个要搞一个万级接入量的算法功能压测程序,查了一下网上的相关资料。测试方案主要参考了下面这篇文章,但是实现和测试方式不同。

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阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容