zoukankan      html  css  js  c++  java
  • Java并发测试

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

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

    
    
  • 相关阅读:
    流行的as3内存释放hack的方法
    干掉这个网页
    Flex元标签笔记Event
    javascript for oop
    asdoc 注释格式
    怎么比较word文档,怎么比较excel文档
    AS3匿名函数的this指向
    SVN空间
    CodeForces 315.D Sereja and Periods
    Html5 filltext
  • 原文地址:https://www.cnblogs.com/maohuidong/p/7866629.html
Copyright © 2011-2022 走看看