性能优化之设计层优化篇(常用优化组件和方法)

    可用于系统性能优化的组件有缓冲、缓存两个组件;

    常用的几种优化思想:池化对象、并行代替串行、负载均衡;

    1、缓冲(Buffer)

           缓冲区是一块特定的内存区域。开辟缓冲区的目的是通过缓解应用程序上下层之间的性能差异,从而起到提高系统性能。(日常生活动的漏斗就是这个道理)

           注意:缓冲可以协调下层组件和下层组件的性能差。当上层组件性能优于下层组件时,可以有效的减少上层组件对下层组件的等待时间。

           缓冲最常用的场景就是提高I/O的速度。JDK中也有不少I/O组件都提供了缓冲功能。例如:BufferedWriter、BufferedOutputStream

           以BufferedWriter为例:
      public class  WriterTest {
          public void test(){
              try {
                   Writer writer = new FileWriter(new File("D:\\opt\\1.jpg"));
                   long begin = System.currentTimeMillis();
                   for(int i=0;i<1000000;i++){
                      writer.write(i);
                   }
                   writer.close();
                   System.out.println("spend:"+(System.currentTimeMillis()-begin));
               } catch (IOException e) {
                   // TODO Auto-generated catch block
                   e.printStackTrace();
               }
          }
          
          public void test1(){
              try {
                  Writer writer = new BufferedWriter(new FileWriter(new File("D:\\opt\\1.jpg")));
                  long begin = System.currentTimeMillis();
                  for(int i=0;i<1000000;i++){
                      writer.write(i);
                  }
                  writer.close();
                  System.out.println("buffer_spend:"+(System.currentTimeMillis()-begin));
              } catch (IOException e) {
                  // TODO Auto-generated catch block
                  e.printStackTrace();
              }
          }
          
          public static void main(String[] args) {
              WriterTest test = new WriterTest();
             test.test(); 
              test.test1(); 
          }
      }

    2、缓存(Cache)
          缓存(Cache)是为提升系统性能而开辟的一块内存空间。

          主要作用:暂存数据处理结果,并提供下次访问使用。通过将来之不易的数据处理结果暂存起来,当有其他线程、客户端需要查询相同的数据资源时直接使用,这样就可以省略对这些数据的处理流程,而直接从缓存中获取处理结果。

          HashMap就可以实现简单的缓存。(注:线程不安全的

     public class CacheTest {
         //参数介绍:2000为缓存最大值;0.75f为负载因子;true为按照访问顺序,false为按照插入顺序
         static LinkedHashMap<String, Object> cache = new LinkedHashMap<String, Object>(2000,0.75f,true){

             private static final long serialVersionUID = 1L;
        
             @Override
             protected boolean removeEldestEntry(Map.Entry<String, Object> eldest) { //超过2000最大值时,删除最老、最不常用的数据
                 return size() > 2000;
             }
        
         };
    
         public static void main(String[] args) {
             CacheTest.cache.put("a", "b");
             System.out.println(cache.get("a")+"==="+cache.size());
         }
    
     }
    3、对象复用--池

    4、并行替代串行

    5、负载均衡

          以网站应用为例,如果并发数非常多,单台服务器无法承受时,为保证应用程序的服务质量,就需要使用多台服务器协同工作,将系统负载尽可能均匀地分配到各个服务器节点上;当某一个服务节点宕(dang)机时,其他节点也可以保证服务正常运行。

          注意:在使用负载均衡时,使用Session信息将会存在信息不同步问题,当然通过复制Session信息在所有的节点上保持一致可以解决不同步问题,但是会出现新的问题,就是很容易造成网络繁忙,影响系统效率。所以综上所述我们可以根据实际情况而定,使用cookie方式保存信息。

    6、时间换空间

          时间换空间通常用于嵌入式设备或者内存、硬盘空间不足的情况。通过使用牺牲CPU的方式,获得原本需要更多内存或者硬盘空间才能完成的工作。

          举个非常简单的时间换空间的算法,实现a、b两个变量的值交换。交换两个变量最常用的方法是使用一个中间变量,而引入额外的变量就意味着要使用更多的空间。采用下面的方法则可以免除中间变量,而达到变量变换的目的,代价是引入更多的CPU运算。

     public class SJHKJ {

         public static void main(String[] args) {
             int a = 1;
             int b = 2;
             System.out.println("a="+a+"-----b="+b);
             a = a+b;
             b = a-b;
             a = a-b;
             System.out.println("a="+a+"-----b="+b);
         }
    
     }
    7、空间换时间

          与时间换空间的方法相反,空间换时间则是尝试使用更多的内存或者磁盘空间换取CPU资源或者网络资源等,通过增加系统的内存消耗,来加快程序的运行速度。典型的应用实例就是缓存。

public class KJHSJ {
    
    public static int arrayLen = 1000000;
    
    public static void main(String[] args){
        int[] a = new int[arrayLen];
        int[] old = new int[arrayLen];
        Map<Integer, Object> map = new HashMap<Integer, Object>();
        int count = 0;
        while(count<a.length){ //初始化数组数据
            int value = (int)(Math.random()*arrayLen*10)+1;
            if(map.get(value)==null){
                map.put(value, value);
                a[count] = value;
                count++;
            }
        }
        System.arraycopy(a, 0, old, 0, a.length);//这里只是为了保存原有数组
        long start = System.currentTimeMillis();
        Arrays.sort(a);
        System.out.println("Arrays.sort spend:"+(System.currentTimeMillis()-start)+" ms");
        System.arraycopy(old, 0, a, 0, old.length);//恢复原有数据
        start = System.currentTimeMillis();
        spaceToTime(a);
        System.out.println("spaceToTime spend:"+(System.currentTimeMillis()-start)+" ms");
    }
    
    public static void spaceToTime(int[] array){
        int i=0;
        int max = array[0];
        int l = array.length;
        for(i = 1;i<l;i++){
            if(array[i]>max){//找到最大值
                max = array[i];
            }
        }
        int[] temp = new int[max+1]; //分配临时空间
        for(i=0;i<l;i++){
            temp[array[i]] = array[i];  //以索引下标来表示数字大小
        }
        int j =0;
        int max1=max+1;
        for(i=0;i<max1;i++){  //线性复杂度
            if(temp[i]>0){
                array[j++] = temp[i];
            }
        }
    }
}
          使用spaceToTime()实现数据的排序耗时要比使用JDK自带的数组排序方法Arrays.sort()的排序要节省一倍的时间。(数据100万,运行在我的机器上)

          之所以速度要优于JDK自带的方法,是因为它不计空间成本,以数组的索引下标来表示数据的大小,这样就避免了数字间的相互比较。

          注意:如果数组中的元素不多时或者当前服务器的CPU运算能力很强,那么JDK自带的排序方法Arrays.sort()的执行速度不一定比spaceToTime()慢,视情况而定。

         


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yan_jl

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值