静态方法在高并发情况下对性能的影响

因为项目需要,在开发过程中写了大量的工具类,而且为了调用方便,工具类中的方法全部是静态方法。今天,脑袋里灵光一闪,突然就想,如果在高并发的情况下,同时去调用工具类的静态方法,会不会导致严重的性能问题?

有了想法,就要付诸于行动,于是,本人本着精益求精的精神,写了几个测试类如下:

COMUT类是主类,负责生成大量的线程实例。

import java.util.Date;

/**
 * @Title: COMUT.java
 * @Copyright (C) 2015 <span style="font-family: Arial, Helvetica, sans-serif;">卓盐</span>
 * @Description:
 * @Revision History:
 * @Revision 1.0 2015-5-19  卓盐
 */

/**
 * @ClassName: COMUT
 * @Description: Description of this class
 * @author <a href="mailto:songfuhong@szlongtu.com">卓盐</a>于 2015-5-19 下午03:15:40
 */

public class COMUT {

    public COMUT() {

    }

    public static void main(String[] args) {
        int times = 5000;
        int type = 1;
        try {
            Date setTime = new Date();
            // 设定为启动程序后的2s执行
            setTime.setTime(setTime.getTime() + 5000);
            // 测试多线程情况下的性能问题
            Thread[] thread = new Thread[times];
            for (int i = 0; i < times; i++) {
                thread[i] = new Thread(new ThreadTest("thread" + i, setTime, type));
            }
            for (int i = 0; i < times; i++) {
                thread[i].start();
            }

            for (int i = 0; i < times; i++) {
                thread[i].join();
            }
            // 等待所有子线程执行完毕后,输出下面的内容
            System.out.println("本次测试方案:" + type + "。最快:" + CulculateUtil.getMin() + "ms。最慢:" + CulculateUtil.getMax()
                    + "ms。平均:" + CulculateUtil.getSum() / CulculateUtil.getTimes() + "ms.");
        } catch (Exception e) {

            e.printStackTrace();

        }

    }
}

ICUtils是工具类,其中的两个静态方法,一个是将15位身份证转化为18位,另一个是校验15位身份证号码的正确性。

/**
 * @Title: IdentiFierChanslateUtils.java
 * @Copyright (C) 2015 <span style="font-family: Arial, Helvetica, sans-serif;">卓盐</span>
 * @Description:
 * @Revision History:
 * @Revision 1.0 2015-5-19  卓盐
 */

/**
 * @ClassName: IdentiFierChanslateUtils
 * @Description: Description of this class
 * @author <a href="mailto:songfuhong@szlongtu.com">卓盐</a>于 2015-5-19 下午03:17:16
 */

public class ICUtils {
    /**
     * 修补15位居民身份证号码为18位
     * @param personIDCode
     * @return
     */

    public static String fixPersonIDCode(String personIDCode)

    {

        if (personIDCode == null || personIDCode.trim().length() != 15) {

            return personIDCode;

        }

        String id17 = personIDCode.substring(0, 6) + "19" + personIDCode.substring(6, 15); // 15为身份证补\'19\'

        // char[] code =
        // {\'1\',\'0\',\'X\',\'9\',\'8\',\'7\',\'6\',\'5\',\'4\',\'3\',\'2\'};
        // //11个
        char[] code = {'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2' }; // 11个

        int[] factor = {0, 2, 4, 8, 5, 10, 9, 7, 3, 6, 1, 2, 4, 8, 5, 10, 9, 7 }; // 18个;

        int[] idcd = new int[18];

        int i;

        int j;

        int sum;

        int remainder;

        for (i = 1; i < 18; i++)

        {

            j = 17 - i;

            idcd[i] = Integer.parseInt(id17.substring(j, j + 1));

        }

        sum = 0;

        for (i = 1; i < 18; i++)

        {

            sum = sum + idcd[i] * factor[i];

        }

        remainder = sum % 11;

        String lastCheckBit = String.valueOf(code[remainder]);

        return id17 + lastCheckBit;

    }

    /**
     * 判断是否是有效的18位或15位居民身份证号码
     * @param identityId :18位或15位居民身份证号码
     * @return:true: 有效的18位或15位居民身份证号码
     */

    public static boolean isIdentityId(String identityId) {

        if (isEmpty(identityId))
            return false;

        try {

            if (identityId.length() == 18) {

                String identityId15 = identityId.substring(0, 6) + identityId.substring(8, 17);

                // System.out.println("the identityId15 is : "+identityId15);

                if (fixPersonIDCode(identityId15).equalsIgnoreCase(identityId)) {

                    return true;

                } else {

                    return false;

                }

            } else if (identityId.length() == 15) {

                try {

                    Long.parseLong(identityId);

                    return true;

                } catch (Exception ex) {

                    return false;

                }

            } else {

                return false;

            }

        } catch (Exception ex) {

            return false;

        }

    }

    /**
     * 判断是否为空串""
     */

    public static boolean isEmpty(String sValue) {

        if (sValue == null)
            return true;

        return sValue.trim().equals("") ? true : false;

    }
}

ICUtilsInstance中的内容和ICUtils中完全一致,只是其中的方法都是实例化方法。

/**
 * @Title: IdentiFierChanslateUtils.java
 * @Copyright (C) 2015 <span style="font-family: Arial, Helvetica, sans-serif;">卓盐</span>
 * @Description:
 * @Revision History:
 * @Revision 1.0 2015-5-19  卓盐
 */

/**
 * @ClassName: IdentiFierChanslateUtils
 * @Description: Description of this class
 * @author <a href="mailto:songfuhong@szlongtu.com">卓盐</a>于 2015-5-19 下午03:17:16
 */

public class ICUtilsInstance {
    /**
     * 修补15位居民身份证号码为18位
     * @param personIDCode
     * @return
     */

    public String fixPersonIDCode(String personIDCode)

    {

        if (personIDCode == null || personIDCode.trim().length() != 15) {

            return personIDCode;

        }

        String id17 = personIDCode.substring(0, 6) + "19" + personIDCode.substring(6, 15); // 15为身份证补\'19\'

        // char[] code =
        // {\'1\',\'0\',\'X\',\'9\',\'8\',\'7\',\'6\',\'5\',\'4\',\'3\',\'2\'};
        // //11个
        char[] code = {'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2' }; // 11个

        int[] factor = {0, 2, 4, 8, 5, 10, 9, 7, 3, 6, 1, 2, 4, 8, 5, 10, 9, 7 }; // 18个;

        int[] idcd = new int[18];

        int i;

        int j;

        int sum;

        int remainder;

        for (i = 1; i < 18; i++)

        {

            j = 17 - i;

            idcd[i] = Integer.parseInt(id17.substring(j, j + 1));

        }

        sum = 0;

        for (i = 1; i < 18; i++)

        {

            sum = sum + idcd[i] * factor[i];

        }

        remainder = sum % 11;

        String lastCheckBit = String.valueOf(code[remainder]);

        return id17 + lastCheckBit;

    }

    /**
     * 判断是否是有效的18位或15位居民身份证号码
     * @param identityId :18位或15位居民身份证号码
     * @return:true: 有效的18位或15位居民身份证号码
     */

    public boolean isIdentityId(String identityId) {

        if (isEmpty(identityId))
            return false;

        try {

            if (identityId.length() == 18) {

                String identityId15 = identityId.substring(0, 6) + identityId.substring(8, 17);

                // System.out.println("the identityId15 is : "+identityId15);

                if (fixPersonIDCode(identityId15).equalsIgnoreCase(identityId)) {

                    return true;

                } else {

                    return false;

                }

            } else if (identityId.length() == 15) {

                try {

                    Long.parseLong(identityId);

                    return true;

                } catch (Exception ex) {

                    return false;

                }

            } else {

                return false;

            }

        } catch (Exception ex) {

            return false;

        }

    }

    /**
     * 判断是否为空串""
     */

    public boolean isEmpty(String sValue) {

        if (sValue == null)
            return true;

        return sValue.trim().equals("") ? true : false;

    }
}


最后一个类ThreadTest,是线程类,构造函数需传入两个参数,一个是线程名,一个是设定的时间。线程主体run方法中,while循环负责校验当前时间是否已到设定时间。到了设定时间就去调用工具类中的两个方法。并将调用的时间记录下来,并输出。

/**
 * @Title: ThreadTest.java
 * @Copyright (C) 2015 <span style="font-family: Arial, Helvetica, sans-serif;">卓盐</span>
 * @Description:
 * @Revision History:
 * @Revision 1.0 2015-5-19  卓盐
 */

/**
 * @ClassName: ThreadTest
 * @Description: Description of this class
 * @author <a href="mailto:songfuhong@szlongtu.com">卓盐</a>于 2015-5-19 下午03:43:45
 */

public class ThreadTest implements Runnable {
    /**
     * @Fields threadName : Description
     */
    private String threadName;
    /**
     * @Fields setTime : Description
     */
    private Date setTime;

    /**
     * @Fields ic : Description
     */
    ICUtilsInstance ic;
    /**
     * @Fields type : Description
     */
    int type;

    /**
     * .
     * <p>
     * Title: run
     * </p>
     * <p>
     * Description:
     * </p>
     * @see java.lang.Runnable#run()
     */
    @Override
    public void run() {
        while (true) {
            Date d = new Date();
            if (d.after(setTime))
                break;
        }
        Date d1 = new Date();
        if (type == 1) {
            ICUtils.fixPersonIDCode("650103760113073");
            ICUtils.isIdentityId("650103760113073");
        } else if (type == 2) {
            ic = new ICUtilsInstance();
            ic.fixPersonIDCode("650103760113073");
            ic.isIdentityId("650103760113073");
        } else if (type == 3) {
            ic.fixPersonIDCode("650103760113073");
            ic.isIdentityId("650103760113073");
        }
        Date d2 = new Date();
        long dif = d2.getTime() - d1.getTime();
        System.out.println("线程名为:" + threadName + "的线程,运行时间为:" + dif + "ms.");
        CulculateUtil.finish(dif);
    }

    /**
     * 创建一个新的实例 ThreadTest.
     * @param threadName
     */
    public ThreadTest(String threadName, Date setTime, int type) {
        super();
        this.threadName = threadName;
        this.setTime = setTime;
        this.type = type;
        if (type == 3) {
            ic = new ICUtilsInstance();
        }
    }

}

还有一个类,用来统计分析用。

/**
 * @Title: CulculateUtil.java
 * @Copyright (C) 2015 <span style="font-family: Arial, Helvetica, sans-serif;">卓盐</span>
 * @Description:
 * @Revision History:
 * @Revision 1.0 2015-5-19  卓盐
 */

/**
 * @ClassName: CulculateUtil
 * @Description: Description of this class
 * @author <a href="mailto:songfuhong@szlongtu.com">卓盐</a>于 2015-5-19 下午04:10:06
 */

public class CulculateUtil {
    /**
     * @Fields sum : Description
     */
    private static long sum = 0;
    /**
     * @Fields max : Description
     */
    private static long max = 0;
    /**
     * @Fields min : Description
     */
    private static long min = 999999999;
    /**
     * @Fields times : 调用次数
     */
    private static int times = 0;

    /**
     * 某个线程结束时需要回掉的方法.
     * @param dif 花费时间
     * @throws
     */
    public static void finish(long dif) {
        times++;
        if (dif < min) {
            min = dif;
        }
        if (dif > max) {
            max = dif;
        }
        sum += dif;
    }

    /**
     * @return max
     */
    public static long getMax() {
        return max;
    }

    /**
     * @param max 要设置的 max
     */
    public static void setMax(long max) {
        CulculateUtil.max = max;
    }

    /**
     * @return min
     */
    public static long getMin() {
        return min;
    }

    /**
     * @param min 要设置的 min
     */
    public static void setMin(long min) {
        CulculateUtil.min = min;
    }

    /**
     * @return times
     */
    public static int getTimes() {
        return times;
    }

    /**
     * @param times 要设置的 times
     */
    public static void setTimes(int times) {
        CulculateUtil.times = times;
    }

    /**
     * @return sum
     */
    public static long getSum() {
        return sum;
    }

    /**
     * @param sum 要设置的 sum
     */
    public static void setSum(long sum) {
        CulculateUtil.sum = sum;
    }

}


本人在测试时,分别用100、1000和5000个线程进行了9次测试。在不同线程数情况下,分别调用了静态方法,在方法体中实例化并调用实例方法,及在构造方法中实例化并调用实例方法,测试结果如下:

线程数静态方法方法中实例化构造方法中实例化
最快平均最慢最快平均最慢最快平均最慢
1001+0+0=17+5+3=2515+16+11=422+0+0=26+4+9=1913+14+17=440+0+0=01+1+0=213+15+5=33
10000+0+0=024+11+26=6168+63+109=2400+0+0=03+22+2=2765+68+66=1990+0+0=024+14+26=6452+47+65=164
50000+0+0=07+17+76=10094+162+310=5660+0+0=012+15+7=34267+114+102=4830+0+0=00+0+4=455+78+81=214
总和1186848280726070411

总结:在并发数较少的情况下,在构造方法中实例化并在方法中调用略占优,但三者性能无太大差别。当并发数较多时,尤其大并发情况下,优先推荐构造方法中实例化,再其次是方法中实例化,最后再是静态方法。高并发情况下,静态方法对性能影响比较大

附件中上传源码及excel格式的测试结果,供大家参考。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值