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

来源:互联网 发布:海康网络摄像机驱动 编辑:程序博客网 时间:2024/06/05 07:39
    可用于系统性能优化的组件有缓冲、缓存两个组件;

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

    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()慢,视情况而定。

         


0 0