当前位置:编程学习 > JAVA >>

Android应用开发提高系列(2)——《Practical Java 中文版》读书笔记(下)

正文
注意:条目和用语可能与书籍有所出入,但尽量保持原样加一些自己的理解。
  一、性能
    1. 先把焦点放在设计、数据结构和算法身上
      备注:良好的设计、明智的选择数据结构和算法可能比高效代码更重要。
 
    2.  不要依赖编译器优化技术
 
    3.  理解运行时(runtime)代码优化
      备注:JIT将bytecode于运行时转换为本地二进制码,从而提高性能。因此编译后代码被执行次数越多,本机代码生成代价就很合算。
 
    4.  连接字符串使用StringBuffer要比String快,尤其是大量字符串拼接
 
    5.  将对象创建成本降至最小
      备注:复用既有对象,不要创建非必要的对象,只在需要的时候才创建它们。
 
    6.  将同步化(synchronization)降至最低
      备注:如果synchronized函数抛出异常,则在异常离开函数之前,锁会自动释放。如果整个函数都需要被同步化,为了产生体积较小且执行速度较快的代码,请优先使用函数修饰符,而不是在函数内使用synchronized代码块。
 
    7.  尽可能使用stack变量
      备注:如果在函数中频繁访问成员变量、静态变量,可以用本地(local)变量替代,最后操作完后再赋值给成员/静态变量。
 
    8.  尽可能的使用static、final和private函数
      备注:此类函数可以在编译期间被静态决议(statically resolved),而不需要动态议决(dynamic resolved)。(子类无法覆写)
 
    9.  类的成员变量、静态变量都有缺省值,务须重复初始化
      备注:记住,本地变量没有缺省值(例如函数内定义的变量)。
 
    10.  尽可能的使用基本数据类型
      备注:如int、short、char、boolean,使得代码更快更小。
 
    11.  不要使用枚举器(Enumeration)和迭代器(Iterator)来遍历Vector
      备注:使用for循环+get()
 
    12.  使用System.arraycopy()来复制数组
      备注:使用System.arraycopy()代替for循环,可以产生更快的代码。如:
        public void copyArray(int[] src, int[] dest) {
            int size = src.length;
            System.arraycopy(src, 0, dest, 0, size);
        }
 
      System.arraycopy()是以native method实现的,可以直接、高效的移动原始数组到目标数组,因此它执行速度更快。
 
    13.  优先使用数组,然后才考虑Vector和ArrayList,理由:
      a).  Vector的get()是同步的
      b).  ArrayList基本上就是一个非线程同步的Vector,比Vector要快
      c).  ArrayList和Vector添加元素或移除元素都需要重新整理数组。
      备注:不要仅仅因为手上有个数不定的数据需要存储,就毫无选择的使用Vector或ArrayList。可以考虑创建一个足够大的数组,通常这样可能会浪费内存,但性能上的收益可能超过内存方面的代价。
 
    14.  手工优化代码
      a).  剔除空白函数和无用代码
      b).  削减强度
        备注:以更高效的操作替换成本昂贵的操作。一个常见的优化手法是使用复式复制操作符(如+=、-=)。
      c).  合并常量
        备注:将变量声明为final,使得操作在编译器就进行。
      d).  删减相同的子表达式
        备注:可用一个临时变量代替重复的表达式。
      e).  展开循环
        备注:如循环次数少且已知循环次数,可展开去掉循环结构,直接访问数组元素。缺点是会产生更多代码。
      f).  简化代数
        备注:使用数学技巧来简化表达式。(例如从1+..+100的问题)
      g).  搬移循环内的不变式
        备注:循环内不变化的表达式可用移至循环外,不必重复计算表达式。
 
    15.  编译为本机代码
      备注:将程序的某部分编译为本机二进制代码,然后通过JNI访问。
 
  二、多线程
    1.  对于实例(instance)函数,同步机制锁定的是对象,而不是函数和代码块。
      备注:函数或代码块被声明为synchronized并非意味它在同一时刻只能有一个线程执行(同一对象不同线程调用会阻塞)。Java语言不允许将构造函数声明为synchronized。
 
    2.  同步实例函数和同步静态函数争取的是不同的locks。
      备注:两者均非多线程安全,可以使用实例变量进行同步控制,如(byte[] lock = new byte[0]),比其他任何对象都经济。
 
    3.  对于synchronized函数中可被修改的数据,应使之成为private,并根据需要提供访问函数。如果访问函数返回的是可变对象,那么可以先克隆该对象。
 
    4.  避免无谓的同步控制
      备注:过度的同步控制可能导致代码死锁或执行缓慢。再次提醒,当一个函数声明为synchronized,所获得的lock是隶属于调用此函数的那个对象。
 
    5.  访问共享变量时请使用synchronized或volatile
      备注:如果并发性很重要,而且不需要更新很多变量,则可以考虑使用volatile。一旦变量被声明为volatile,在每次访问它们时,它们就与主内存进行一致化。如果使用synchronized,只在取得lock和释放lock时候才一致化。
 
    6.  在单一操作(single operation)中锁定所有用到的对象
      备注:如果某个同步函数调用了某个非同步实例函数来修改对象,它是线程安全的。使用同步控制时,一定要对关键字synchronized所作所为牢记在心。它锁定的是对象而非函数或代码。
 
    7.  以固定而全局性的顺序取得多个locks(机制)以避免死锁。P/181~P/185
      备注:嵌入[锁定顺序]需要额外的一些工作、内存和执行时间。
 
    8.  优先使用notifyAll()而非notify()
      备注:notify()和notifyAll()用以唤醒处以等待状态的线程,waite()则让线程进入等待状态。notify()仅仅唤醒一个线程。
 
    9.  针对wait()和notifyAll()使用旋转锁(spin locks)
      备注:旋转锁模式(spin-lock pattern)简洁、廉价,而且能确保等待着某个条件变量的代码能循规蹈矩。
 
    10.  使用wait()和notifyAll()替代轮询(polling loops)
      备注:调用wait()时会释放同步对象锁,暂停(虚悬,suspend)此线程。被暂停的线程不会占用CPU时间,直到被唤醒。如:
 
            public void run()
            {
                int data;
                while(true){
                    synchronized (pipe) {
                        while((data = pipe.getDate()) == 0){
                            try{
                                pipe.waite();
                            }
                            catch(InterruptedException e){}
                        }
                    }
         &n

补充:移动开发 , Android ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,