Java编程规范-性能编程_第1页
Java编程规范-性能编程_第2页
Java编程规范-性能编程_第3页
Java编程规范-性能编程_第4页
Java编程规范-性能编程_第5页
已阅读5页,还剩57页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、Java 性能编程规范1 字符串操作规则 1.1:需要同步的情况下,采用 StringBuffer 处理字符串拼装。说明编程时,当字符串连接超过 3 次的情况下,请使用 StringBuffer 而不是“ + ”。因为 String 是不变( Immutable )对象类,使用“ +”会创建新 String 临时对象,因此增加了创建与回 收临时对象的开销。 StringBuffer 对象是可变 ( mutable )对象类, 不存在该问题。 在 JDK1.5 之后,增加了 StringBuilder 类,在单线程中使用时, StringBuilder 的效率要高于 StringBuffer 。

2、 详见规则 1.2。【示例】String str = strA + StrB + StrC;/会创建临时对象 strA + StrB可修改为:StringBuffer strBuf = new StringBuffer(128); strbuf.append(strA).append(strB).append(strC);规则 1.2:不需要同步的情况下,使用 StringBuilder 处理字符串拼装。说明从 JDK 5 开始, JDK 为 StringBuffer 补充了一个单个线程使用的等价类 StringBuilder 。StringBuilder 与 StringBuffer 支持所

3、有相同的操作,不同点在于 StringBuilder 的方法不是 线程安全的, StringBuffer 的方法是线程安全的,因此 StringBuilder 速度更快。所以,当 不存在线程安全问题时,应该优先使用 StringBuilder 。示例】String str = strA + StrB + StrC;/ 会创建临时对象 strA + StrB当不需要考虑线程安全问题时,可修改为:StringBuilder strBuilder = new StringBuilder(128); strBuilder.append(strA).append(strB).append(strC);规

4、则 1.3: 避免频繁或对大对象使用 String 类的 replaceAll 方法。说明因为 String 是不变对象类,对象在执行 replaceAll 方法时,因为替换操作将创建大量新的 临时对象,这些对象的创建和回收将消耗系统性能。如果要进行这样的操作,考虑使用 Pattern 类和 Matcher 类。【示例】Pattern p = Ppile(cat);Matcher m = p.matcher(one cat two cats in the yard);StringBuffer sb = new StringBuffer();while (m.find()m.

5、appendReplacement(sb, dog);m.appendTail(sb);System.out.println(sb.toString();规则 1.4: 避免大对象使用默认的 toString 方法转换为字符串。说明【示例】规则 1.5:不要通过 new 方式来创建常量字符串。说明在 java 语言中,对于字符串常量,虚拟机会通过常量池机制确保其只有一个实例。常量池中既包括了字符串常量,也包括关于类、方法、接口等中的常量。 当应用程序要创建一 个字符串常量的实例时,虚拟机首先会在常量池中查找,看是否该字符串实例已经存在, 如果存在则直接返回该字符串实例, 否则新建一个实例返回。

6、 我们说常量是可以在编译期 就能被确定的,所以通过 new 方法创建的字符串不属于常量。对于字符串常量,不要通 过 new 方法来进行创建,因为这样可能会导致创建多个不必要的实例。【示例】/ 下面语句将返回 ”Hello! Welcome to NanJing. ”的一个新实例对象String str = new String( ”Hello! Welcome to NanJing. ”);规则 1.6: 使用“ +”拼接常量字符串。说明因为使用“ + ”拼接常量字符串可以在编译期间完成,因此提高了运行时效率。而使用Stringbuilder 或 StringBuffer 进行常量字符串拼接,

7、都是在运行时完成的。因此相对前者, 效率要低。需要强调的是,这里是常量字符串拼接。【示例】String str = “Hello! ”+ “Welcom ”+ “to ”+ “NanJing. ”;建议 1.7: 在使用 StringBuffer 进行字符串操作时,尽量设定初始容量大小。说明StringBuffer 的默认构造函数,其数据 capacity 初始值为 16,在字符串操作过程中,如果 字符串长度达到 capacity 并且需要继续增加时,系统将申请 2倍于原 capacity 的数据空间 作为新的数据空间, 并将之前的数据拷贝到新的数据空间, 原数据空间释放待回收。 为避 免数据

8、空间申请、 数据拷贝, 以及原数据空间的垃圾回收操作开销, 在在使用 StringBuffer 进行字符串操作时, 尽量设定初始容量大小, 使得容量大小足够容纳本身操作的数据。 也 不要申请过大,以免影响其他操作对内存的使用。规则 1.8: 避免通过 String/CharSequence 对象来构建 StringBuffer 对象。说明 使 用 String/CharSequence 对 象 来 构 建 StringBuffer 对 象 时 , 其 初 始 capacity 值 为 String/CharSequence 对象的长度 +16,因此当进一步进行字符串拼装时, 16 个字符空间位

9、 置显得太小,因此将面临进一步的空间扩展问题(参见建议 1.7),消耗性能。建议先设置 恰当的初始容量大小,然后将 String/CharSequence 对象添加进去。【示例】String str = “Hello! Welcome to NanJing. ”;StringBuffer strBuf = new StringBuffer(128);strBuf.append(str);strBuf.append(strA).append(strB).append(strC);规则 1.9: 如果不需要支持正则表达式,使用 indexOf 方法实现字符串查找;说明在 java 中,进行字符串查

10、找匹配时一般有三种实现方式:第一种是调用 String 对象的 indexOf(String str) 方法;第二种是调用 String 对象的 matches(String regex) 方法;第三种是 直接使用正则表达式工具类(包括 Pattern类、Matcher类)来实现匹配。这三种实现方式 的各自特点如下:indexOf(String str) 方法运行速度最快,效率最高,但不支持正则表达式。matches(String regex) 方法性能最差,但支持正则表达式,使用起来简单(该方法性能差的 原因是每调用一次时,就重新对正则表达式编译了一次,新建了一个Pattern 对象出来,而

11、不是重复利用同一个 Pattern 对象)。直接使用正则表达式工具类来实现匹配,可以支持正则表达式,在频繁操作下性能比 matches(String regex) 方法要好很多。规则 1.10: 需要支持正则表达式时,如果频繁进行查找匹配,使用正则表达式工具类实现 查找。说明正则表达式工具类 Pattern 在为其指定字符串正则表达式时必须首先被编译为此类的实 例。然后,得到的实例可用于创建的 Matcher 对象,依照正则表达式,该对象可以与任 意字符序列匹配,因此相对于String类的matches(String regex)方法每次调用均进行一次编 译而言, Pattern 类可以一次编

12、译多次、多处使用,因此可以明显提升效率。【示例】Pattern p = Pattern. compile(a*b);Matcher m = p.matcher(aaaaab);boolea n b = m.matches();StringTokenizer。规则1.11:对于简单的字符串分割,尽量使用自己定义方法或说明在java中,JDK提供了两种方法可以实现字符串的分割:利用String对象提供的split(String regex)方法实现分割;利用StringTokenizer对象实现字符串分割;采用split(String regex)方法,由于使用了正则表达式,性能最差,然而功能性最

13、强;采用StringTokenizer对象分割字符串,性能最强,功能也就相对较弱。2 10读写规则规则2.1:采用非阻塞I/O,避免使用大量通讯线程。说明所谓阻塞方式的意思是指,当试图对该文件描述符进行读写时,如果当时没有东西可读,或 者暂时不可写,程序就进入等待状态,直到有东西可读或者可写为止。而对于非阻塞状态,如果没有东西可读,或者不可写,读写函数马上返回,而不会等待。阻塞式10每个连接必须要开一个线程来处理,并且没处理完线程不能退出。由于每创建一 个线程,就要为这个线程分配一定的内存空间,而且操作系统本身也对线程的总数有一定的限制,因此,如果客户端的请求过多,服务端程序可能会因为不堪重负

14、而拒绝客户端的请求, 甚至服务器可能会因此而瘫痪。非阻塞式IO,由于基于反应器模式,用于事件多路分离和分派的体系结构模式,所以可以利用线程池来处理。事件来了就处理,处理完了就把线程归 还,因此非阻塞IO可以减少通讯线程开销。【示例】代码功能:client多线程请求server端,server接收client的名字,并返回 Hello! +名字的字符格式给 clie nt服务端代码:public class HelloWorldServerString sde;static int BLOCK = 1024;static String name =;protected Selector sele

15、ctor;protected CharsetDecoder decoder;static CharsetEncoder encoder = Charset.forName(GB2312).newEncoder();public HelloWorldServer(int port) throws IOExceptionselector = this.getSelector(port);Charset charset = Charset.forName(GB2312);decoder = charset.newDecoder();/ 获取 Selectorprotected Selector ge

16、tSelector(int port) throws IOExceptionServerSocketChannel serverChannel = ServerSocketChannel.open();Selector selector = Selector.open();serverChannel.socket().bind(new InetSocketAddress(port);serverChannel.configureBlocking(false);serverChannel.register(selector, SelectionKey.OP_ACCEPT);return sele

17、ctor;/监听端口public void listen()tryfor (;)selector.select();Iterator iter = selector.selectedKeys().iterator();while (iter.hasNext()SelectionKey key = (SelectionKey) iter.next();iter.remove();tryprocess(key);catch(Exception e)e.printStackTrace();key.channel().close();catch (lOException e)e.printStackT

18、race();/处理事件protected void process(SelectionKey key) throws lOExceptionif (key.isAcceptable()/接收请求ServerSocketChannel server = (ServerSocketChannel) key.channel();SocketChannel channel = server.accept();/设置非阻塞模式channel.configureBlocking(false);channel.register(selector, SelectionKey.OP_READ);else if

19、 (key.isReadable() /读信息ByteBuffer clientBuffer = ByteBuffer.allocate(BLOCK);SocketChannel channel = (SocketChannel) key.channel();int count = channel.read(clientBuffer);if (count 0)clientBuffer.flip();CharBuffer charBuffer = decoder.decode(clientBuffer);name = charBuffer.toString();SelectionKey sKey

20、 = channel.register(selector, SelectionKey.OP_WRITE); sKey.attach(name);elsechannel.close();clientBuffer.clear();else if (key.isWritable() /写事件Socketchannel channel = (Socketchannel) key.channel();String name = (String) key.attachment();ByteBuffer block = encoder.encode(CharBuffer.wrap(Hello ! + nam

21、e);channel.write(block);SelectionKey sKey = channel.register(selector, SelectionKey.OP_READ); sKey.attach(name);public static void main(String args)int port = 8880;tryHelloWorldServer server = new HelloWorldServer(port);System.out.println(listening on + port);server.listen();catch (IOException e)e.p

22、rintStackTrace();客户端代码:public class HelloWorldClientstatic int SIZE = 10;static InetSocketAddress ip = new InetSocketAddress(localhost, 8880);static CharsetEncoder encoder = Charset.forName(GB2312).newEncoder();static class Message implements Runnableprotected String name;String msg =;public Message

23、(String index) = index;public void run()try/打开Socket通道SocketChannel client = SocketChannel.open();/设置为非阻塞模式client.configureBlocking(false);/打开选择器Selector selector = Selector.open();/注册连接服务端socket动作client.register(selector, SelectionKey.OP_CONNECT);/连接client.connect(ip);/分配内存ByteBuffer buffe

24、r = ByteBuffer.allocate(8 * 1024);int total = 0;for (;)selector.select();Iterator iter = selector.selectedKeys().iterator();while (iter.hasNext()SelectionKey key = (SelectionKey) iter.next(); iter.remove();if (key.isConnectable()SocketChannel channel = (SocketChannel) key.channel(); if (channel.isCo

25、nnectionPending()channel.finishConnect();channel.write(encoder.encode(CharBuffer.wrap(name);else if (key.isReadable()SocketChannel channel = (SocketChannel) key.channel();int count = channel.read(buffer);if (count 0)total += count;buffer.flip();while (buffer.remaining() 0)byte b = buffer.get();msg +

26、= (char) b;buffer.clear();System.out.println(msg);msg =;elseclient.close();break;channel.register(selector, SelectionKey.OP_WRITE);else if (key.isWritable()SocketChannel channel = (SocketChannel) key.channel();ByteBuffer block = encoder.encode(CharBuffer.wrap(name); channel.write(block);channel.regi

27、ster(selector,SelectionKeysKey=SelectionKey.OP_READ);catch (lOException e)public static void main(String args) throws lOException String names = new StringSIZE;for (int index = 0; index SIZE; index+)namesindex = jeff + index + ;new Thread(new Message(namesindex).start();规则2.2:进行IO读写操作时,使用缓冲机制。说明使用缓冲

28、方式的读写比不使用缓冲方式的读写性能要高很多,这是因为缓冲读写一次可以完成大量数据的读写操作,最大值为一个缓冲区大小,因此相对字节读写、字符、整数、浮点 数、复合数据的读写,其10次数可以明显减少,从而提升效率。【示例】FileInputStream fin = new FileInputStream(d:/test.rar);FileOutputStream fout = new FileOutputStream(d:/e/test.rar);BufferedI nputStream bufferI nput =new BufferedI nputStream(fi n);BufferedO

29、utputStream bufferOutput =new BufferedOutputStream(fout);int c=-1;trywhile (c = bufferI nput.read() != -1)bufferOutput.write(c);fin allybufferI nput.close();bufferOutput.close();规则2.3:优先使用字节10进行读写,而避免用字符10进行读写。说明基于字符的 IO 读写比基于字节的 IO 读写要慢很多, 其原因是基于字符的 IO 读写多了频繁 的字符转换操作。另外,一个 char 用两个字节保存字符,而 byte 只需要

30、一个,因此用 byte 保存字符消耗的内存和需要执行的机器指令更少。更重要的是,用 byte 避免了字符编码方 式(例如,默认为 Unicode )的转换,因此,如果可能的话,应尽量使用 byte 替代 char。 【示例】参见“规则 2.2 ”规则 2.4: 在 IO 操作中,必须定义 finally 代码段执行 IO 关闭操作。说明finally 代码段的作用是, 无论 try 代码段是否正确运行, finally 代码总是被执行。而在 IO 操 作中,经常会出现 IO 操作异常情形而导致文件句柄没有关闭释放,致使文件句柄被逐步消 耗而是系统瘫痪。如果在 finally 代码段执行 IO

31、关闭操作,则可以避免这一情况发生。 【示例】参见“规则 2.2 ”建议 2.5: 引入高性能 IO 方式,如: AIO (IBM AIO4J )。说明同步 IO 处理是指客户端在发送请求后,必须得在服务端有回应后才发送下一个请求,否则 必须等待, 因此同步 IO 性能消耗等于通讯链路消耗 +服务器消息处理消耗。 通信异步是指客 户端在发送请求后, 不必等待服务端的回应就可以继续发送下一个请求, 服务器完成请求处 理后, 将响应结果传送到客户端, 客户端以响应结果为参数完成要求的回调处理, 可见异步 IO的处理性能消耗基本上等于服务器处理消耗。而且通常情况下,服务器使用多核CPU可以并发处理客户

32、端的多个请求消息,因此使用异步10,可以大大增加处理效率。【示例】规则 2.1建议2.6: 使用内存映射文件(memory-mapped file)将大文件中的某个区域(region)映射 到内存中,通常比使用read、 write 方法更有效。内存映射文件 I/0 是一种读和写文件数据的方法,它可以比常规的基于流或者基于通道的I/0 快得多。 内存映射文件 (memory-mapped file) 能让你创建和修改那些大到无法读入内存 的文件。 有了内存映射文件, 你就可以认为文件已经全部读进了内存, 然后把它当成一个非 常大的数组来访问。这种解决思路也能大大简化修改文件的代码。内存映射文件

33、I/0 是通过使文件中的数据变成为内存数组的内容来完成的, 一般来说也只有文件中实际读取或者写 入的部分才会被映射到内存中。 尽管创建内存映射文件相当简单, 但是向它写入可能是危险 的。仅只是改变数组的单个元素这样的简单操作, 就可能会直接修改磁盘上的文件, 修改数 据与将数据保存到磁盘是不分开的。public static void main(String args) throws Exception MappedByteBuffer out =new RandomAccessFile(test.dat,rw).getChannel().map(FileChannel.MapMode.REA

34、D_WRITE, 0, length);for(int i = 0; i length; i+)out.put(byte)x);System.out.println(Finished writing);for(int i = length/2; i 0) /符合条件创建 StringBuilder 对象StringBuilder strBuilder = new StringBuilder(1024);for(int i = 0; i strs.length; i+)strBuilder.append(strsi).append(“ n ” );Return strBuilder.toStri

35、ng();return null;规则 3.2: 对象的创建应尽量在for、 while 等循环外面创建,在循环里面进行重用。说明临时对象的创建与释放都需要消耗 CPU 和内存,减少临时对象创建释放,进行对象重用有 利于提升系统性能。 在循环内创建临对象不利于对象的重用, 会增加系统处理负担, 如果在 循环外创建,则有机会复用这些对象。【示例】优化前:public void executeColumnFilter(String selectedValues)for (int tableIndex = 0; tableIndex size; tableIndex+) Vector rowData

36、 = (Vector) tableDataV .get(tableIndex); String detailMsgStr = getDetailMsgStr(tableIndex);private String getDetailMsgStr(int tableIndex)String detailMsgStr = ;/ 消息详细解释码流字符串HashMap detailParameter = new HashMap(); / 该对象没有重用优化后:public void executeColumnFilter(String selectedValues) Map map=new HashMa

37、p(3); / 在 for 循环外面创建对象,在使用时进行重用。for (int tableIndex = 0; tableIndex size; tableIndex+)Vector rowData = (Vector) tableDataV .get(tableIndex);map.clear();String detailMsgStr = getDetailMsgStr(tableIndex,map);J JJ Jprivate String getDetailMsgStr(int tableIndex,Map map)String detailMsgStr = ;/ 消息详细解释码流字

38、符串J J规则 3.3: 对于高频度使用的对象,需要进行单独优化处理给以重用(如:对象池) 。 说明对象的创建和释放会消耗系统 CPU ,减少对象的创建和释放有利于提升性能。对于高频度 使用的对象, 为其建立对象池, 在需要对象时从池中提取, 对象使用完成后再归还对象池中, 将可以避免对象的频繁创建和释放操作, 从而大大提升系统性能。 在系统中经常使用的线程 池,连接池就是很好的例子。【示例】(略)规则 3.4: 对象不再使用时,必须及时清除。说明对象需要占用内存, 内存占用或内存消耗的积累将会影响需求内存模块的内存申请, 如果超 过系统允许的最大内存极限, 系统将出现内存溢出的系统异常。 因

39、此对于不再使用的对象必 须及时清除。 例如文件在读写操作完成后, 必须将其关闭, 容器中不再使用的对象应当将其 清空。【示例】略) 规则 3.5: 当使用自定义的类装载器去装载类时,在被装载的类不再使用后,需要保证该 类装载器可以被垃圾回收说明如果类装载器不被垃圾回收掉, 则被该类装载器装载的所有类都不会被卸载掉, 从而导致内 存泄露或无谓的内存占用,甚至产生内存溢出异常。【示例】代码说明:下面的代码只有将类装载器加入 Vector 的操作,没有对应的删除操作,将导致 类装载器不断增加,而由装载器装载的类也不被释放,从而会最终导致系统溢出。public abstract class Class

40、Loader private static native void registerNatives();static registerNatives();/ If initialization succeed this is set to true and security checks will/ succeed. Otherwise the object is not initialized and the object is/ useless.private boolean initialized = false;/ The parent class loader for delegat

41、ionprivate ClassLoader parent;/ Hashtable that maps packages to certs private Hashtable package2certs = new Hashtable(11);/ Shared among all packages with unsigned classes java.security.cert.Certificate nocerts;/ The classes loaded by this class loader. The only purpose of this table/ is to keep the

42、 classes from being GCed until the loader is GCed. private Vector classes = new Vector();/ The initiating protection domains for all classes loaded by this loaderprivate Set domains = new HashSet();/ Invoked by the VM to record every loaded class with this loader.void addClass(Class c) classes.addEl

43、ement(c);规则 3.6: 如果可以使用多个小对象,应尽量避免创建大对象,避免大内存分配失败或引 发垃圾收集;【示例】说明 应该是相对而言的。如果不是超大对象一般也不会出现内存分配异常情况。使用 多个小对象会导致对象多次创建和释放,会增加 CPU 开销。规则 3.7: 程序执行过程中避免自行调用System.gc()。说明java 垃圾回收机制, 一般要等到内存快不够用或系统空闲时才进行回收。 如果代码中调用了System.gc(),也只是告诉虚拟机要回收,但究竟什么时候回收也不是程序能够控制的,由虚 拟机说了算。如果强制调用System.gc(),甚至可能出现垃圾回收处理过于频繁,而影

44、响正常业务处理,降低系统性能。【示例】(略)规则 3.8: 尽量不要将一些大的对象放到需要序列化的对象中。说明对象序列化的目的是便于数据链路上传送和到达目的地的恢复。如果序列化对象中包含大对象,将增加序列操作的 CPU 开销、字节开销,而且增加链路传输开销。所以对于大对象, 最后分清楚哪些是需要传送的, 仅对需要传送的数据序列化, 而不是整个的数据序列化, 即 定制序列化过程。序列化通常是自动完成的, 但也可以对这个过程进行控制。 序列化时, 类的所有数据成员除 了声明为 transient 或 static 成员外都将自动序列化, 对象流不序列化 static 或 transient 变量,

45、 序列化过程不将其加进对象字节流中。如果要对这些数据进行传输,需要重写writeObject()方法,将需要传送变量加入对象字节流,反序列化时,使用readObject() 方法从对象字节流中读取这些数据进行恢复。【示例】class LabeledPoint implements Serializableprivate String label;transient private Point2D.Double point;public LabeledPoint(String str, double x, double y)label = str;point = new Point2D.Doub

46、le(x, y);private void writeObject(ObjectOutputStream out) throws IOException/ 必须通过调用 defaultWriteObject() 方法来写入 /对象的描述以及那些可以被序列化的字段 out.defaultWriteObject();out.writeDouble(point.getX(); out.writeDouble(point.getY();private void readObject(ObjectInputStream in)throws IOException, ClassNotFoundExcept

47、ion/ 必须调用 defaultReadObject() 方法 in.defaultReadObject();double x = in.readDouble() + 1.0;double y = in.readDouble() + 1.0;point = new Point2D.Double(x, y);规则 3.9: 避免过深的继承层次;说明过深的类层次结构不仅会增加开发和维护的复杂度,同时会增加类对象的规模。 类对象规模的增加会导致不必要数据成员的初始化和内存开销,影响性能。 通常来讲, 应将层次结构限制在六级或更少级别。 使用包容结构可以降低类的层次结构, 而且成员对象可以在需要的时

48、 候进行初始化,因此能够提升系统效率。【示例】(略)规则3.10:避免不必要的类型转换(cast)和类型识别;说明类型转换容易导致兼容性错误, 使程序出现错误甚至异常且在编译期又无法发现。 而且类型 转换会增加系统开销, 例如将整形转换成浮点型, 需要增加字节长度和数据处理。 同样进行 类型识别也需要消耗 CPU,因此要尽量避免数据类型转换和类型识别。【示例】/ 创建数据集合对象时指定装载的数据类型private static LinkedList msgLst = new LinkedList()private Message getMessage()Message msg = null;

49、synchronized(msgLst)while(msgLst.isEmpty() try if(endCount.get() = Const.REQ_M_THREAD) return null; msgLst.wait();catch(InterruptedException ex)/ 获取数据时,避免了类型识别与类型转换msg = msgLst.removeFirst();msgLst.notifyAll();return msg;规则3.11:如果类实现了 Cloneable接口,使用clone()方法创建新实例,避免构造函数链 式调用,比使用 new 方法效率要高。说明clone 方

50、法所做的操作是直接复制字段的内容,换句话说,这个操作并不管该字段对应的对 象类型和内容。而使用 new 方法创建新对象,需要一个成员变量一个成员变量地初始化, 需要进行对象识别,又需要根据对象类别进行对应的初始化赋值操作,因此比使用clone()方法效率要低得多。【示例】public class Something implements Cloneableprivate Something obj;public Something cloneSomething()tryobj = (Something)this.clone();catch (CloneNotSupportedException

51、 e)e.printStackTrace();return obj;public Object clone()throws CloneNotSupportedExceptionSomething obj; obj= (Something)super.clone(); return obj;4 排序 /比较规则 4.1: 实现 Comparable 接口支持比较操作,使用高效算法实现compare() 方法。说明JDK 的 Arrays 和 Collections 类提供了很多查找和排序算法,也可以自己实现这些算法。在 进行排序和查找处理中,除了算法本身复杂度会影响性能,compare()方法处

52、理开销也是一个极为关键的因素, 因为每次比较操作都需要调用该函数, 因此需要对该方法实现加以研究, 使用使用高效率算法。【示例】(略)规则 4.2: 避免不必要的等式判断,如: if(flag = true) 改写成 if(flag) 。说明因为逻辑运算flag = true ”其结果等于flag,因此使用if(flag = true)和使用if(flag)的处理 结果是一样的,但显然后者的效率要高,因为减少了一次“=”运算操作。【示例】(略)规则 4.3: 避免频繁执行的条件语句(如:循环条件)中使用复杂表达式。 说明复杂表达式的运算性能较低, 放在频繁执行的条件语句中不利于系统性能。 可以

53、采取对表达 式进行简化的处理, 甚至对表达式中一些不会发生变化的运算, 在条件表达式之外完成运算, 再对计算结果加以重用,从而运行提高效率。【示例】下面的 agent_works(a) 运算与循环处理无关,可以提到循环处理之外。for (i = 0; i MAX; i+) if (agent_works(a) else 优化后:if (agent_works(a) else for (i = 0; i MAX; i+) 规则 4.4: 根据性能需求(时间、空间等)选择合适的排序算法;说明排序算法分内排序和外排序。 内排序是指当待排序的表中记录个数较少, 整个排序过程中所 有的记录都可以保留在内

54、存中的一种排序算法; 外排序是指待排序的记录个数非常多, 以至 于他们必须存储在磁带、 磁盘上的外部文件中, 排序过程中需要多次访问外存的一种排序算 法。即使内排序, 不同的排序算法有不同的时间复杂度和空间复杂度, 时间复杂度小运行效 率高,空间复杂度小所需额外内存开销小。特别是算法本身的实现,如果是使用递归算法, 则需要栈空间消耗。 因此, 对于由递归函数实现的排序算法不宜用于大量数据的排序。如果数据量太大,则需要考虑使用外排序。【示例】(略)5 并发 /多线程规则 5.1: 对共享资源进行同步保护。说明为避免共享资源被并发修改, 或在修改过程中被读取, 需要对其加以保护。 保护措施有多种: 互斥锁、读写锁、信号量等等, 不同类型的锁保护适用于不同的场景并有着不同的性能。互 斥锁一般用于两个线程的读者和写者模式。读写锁一般用于多个线程间的读者和写者模式。 信号量一般应用于生产者和消费者模式。在 JDK1.5 之后,提供了 JAVA 普通数据类型如 boolean、char、 byte、 int 、 short、 long 、 float 、 doubl

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论