美文网首页
模拟多线程高并发 压测程序研究

模拟多线程高并发 压测程序研究

作者: vpike | 来源:发表于2019-07-22 11:20 被阅读0次

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

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通知等待集上的线程,唤醒线程。

代码如下:


  public class Parallellimit {
            public static void main(String[] args) {
                      ExecutorService pool = Executors.newCachedThreadPool();
                      Counts count = new Counts();  
                    //共享操作该计数变量,不能使用int或者integer,Java无法对非对象、和包装  
                   //类进行加锁
                    waitcount.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阻塞线程。

当达到并发量时,阻塞条件失效,线程继续运行。

代码如下:

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直接长时间做条件阻塞
CountDownLatchJava提供的实现阻塞和释放线程的类,尝试是否符合推荐的规律。其中主要包含三个方法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实现高并发〉*/

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方式要减少约一半。

综上,阻塞似乎是最坑爹的一种方式

相关文章

  • 模拟多线程高并发 压测程序研究

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

  • Jmeter压测java接口、Jmeter自定义变量模拟多用户压

    场景:作为开发人员经常需要进行java接口的压测,比如商品抢购、并发量大的活动接口,需要模拟多用户进行并发压测,这...

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

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

  • 5.基于jmeter压测的一些思考

    1.jmeter允许多个线程并发取样,那么,多线程有上限、瓶颈吗? 按我的理解,实际压测过程中,是用4台压测机,一...

  • jmeter(九) 简单压测

    压测策略:不同并发数:10,50,100,200,400 压测结果:并发数:最佳并发用户数、最大并发用户数流量:每...

  • siege工具源码解析

    原理 如果并发用户数为n,那么就会相应创建n个压测线程,每个线程模拟一个用户。除了压测线程之外,主函数会额外生成2...

  • Nginx高并发 ab测压

    静态网页nginx压缩:https://www.bilibili.com/video/av66388283/?p=...

  • 四种方式实现HttpServer并测试负载能力

    1.ServerSocket实现httpServer 1.1 阻塞式 代码: 压测结果: 1.2 多线程 压测结...

  • 锁的优化及注意事项(1)

    实战Java高并发程序设计笔记 在高并发的环境下,激励的锁竞争会导致程序的性能下降。因为多线程应用除了处理功能需求...

  • 流量录制,基于常态化压测

    简介 常态化压测、业务压测、集群压测、全链路压测、等基于特定需求的对后台接口进行的并发式请求,接口自动化压测数据的...

网友评论

      本文标题:模拟多线程高并发 压测程序研究

      本文链接:https://www.haomeiwen.com/subject/sgyilctx.html