说三道四技术文摘-感悟人生的经典句子
说三道四 > 文档快照

Java程序优化的一些最佳实践

HTML文档下载 WORD文档下载 PDF文档下载
本文介绍了Java代码优化的过程,总结了优化Java程序的一些最佳实践,分析了进行优化的方法并解释了性能提升的原因。多角度分析导致性能低的原因并逐个进行优化使得程序性能得到极大提升,代码可读性、可扩展性更强。

作者通过经历的一个项目实例,介绍Java代码优化的过程,总结了优化Java程序的一些最佳实践,分析了进行优化的方法,并解释了性能提升的原因。作者从多个角度分析导致性能低的原因,并逐个进行优化,最终使得程序的性能得到极大提升,增强了代码的可读性、可扩展性。

一、衡量程序的标准
衡量一个程序是否优质,可以从多个角度进行分析。其中,最常见的衡量标准是程序的时间复杂度、空间复杂度,以及代码的可读性、可扩展性。针对程序的时间复杂度和空间复杂度,想要优化程序代码,需要对数据结构与算法有深入的理解,并且熟悉计算机系统的基本概念和原理;而针对代码的可读性和可扩展性,想要优化程序代码,需要深入理解软件架构设计,熟知并会应用合适的设计模式。

  • 首先,如今计算机系统的存储空间已经足够大了,达到了 TB 级别,因此相比于空间复杂度,时间复杂度是程序员首要考虑的因素。为了追求高性能,在某些频繁操作执行时,甚至可以考虑用空间换取时间。
  • 其次,由于受到处理器制造工艺的物理限制、成本限制,CPU主频的增长遇到了瓶颈,摩尔定律已渐渐失效,每隔18个月CPU主频即翻倍的时代已经过去了,程序员的编程方式发生了彻底的改变。在目前这个多核多处理器的时代,涌现了原生支持多线程的语言(如Java)以及分布式并行计算框架(如Hadoop)。为了使程序充分地利用多核CPU,简单地实现一个单线程的程序是远远不够的,程序员需要能够编写出并发或者并行的多线程程序。
  • 最后,大型软件系统的代码行数达到了百万级,如果没有一个设计良好的软件架构,想在已有代码的基础上进行开发,开发代价和维护成本是无法想象的。一个设计良好的软件应该具有可读性和可扩展性,遵循“开闭原则”、“依赖倒置原则”、“面向接口编程”等。
二、项目介绍

本文将介绍笔者经历的一个项目中的一部分,通过这个实例剖析代码优化的过程。下面简要地介绍该系统的相关部分。

该系统的开发语言为Java,部署在共拥有4核CPU的Linux服务器上,相关部分主要有以下操作:通过某外部系统D提供的RESTAPI获取信息,从中提取出有效的信息,并通过JDBC 存储到某数据库系统S中,供系统其他部分使用,上述操作的执行频率为每天一次,一般在午夜当系统空闲时定时执行。为了实现高可用性(HighAvailability),外部系统D部署在两台服务器上,因此需要分别从这两台服务器上获取信息并将信息插入数据库中,有效信息的条数达到了上千条,数据库插入操作次数则为有效信息条数的两倍。

图 1.系统体系结构图


为了快速地实现预期效果,在最初的实现中优先考虑了功能的实现,而未考虑系统性能和代码可读性等。系统大致有以下的实现: 
  1. REST API获取信息、数据库操作可能抛出的异常信息都被记录到日志文件中,作为调试用;
  2. 共有5次数据库连接操作,包括第一次清空数据库表,针对两个外部系统D各有两次数据库插入操作,这5个连接都是独立的,用完之后即释放;
  3. 所有的数据库插入语句都是使用java.sql.Statement类生成的;
  4. 所有的数据库插入语句,都是单条执行的,即生成一条执行一条;
  5. 整个过程都是在单个线程中执行的,包括数据库表清空操作,数据库插入操作,释放数据库连接;
  6. 数据库插入操作的JDBC代码散布在代码中。虽然这个版本的系统可以正常运行,达到了预期的效果,但是效率很低,从通过 REST API获取信息,到解析并提取有效信息,再到数据库插入操作,总共耗时100秒左右。而预期的时间应该在一分钟以内,这显然是不符合要求的。
三、代码优化过程

笔者开始分析整个过程有哪些耗时操作,以及如何提升效率,缩短程序执行的时间。通过REST API获取信息,因为是使用外部系统提供的API,所以无法在此处提升效率;取得信息之后解析出有效部分,因为是对特定格式的信息进行解析,所以也无效率提升的空间。所以,效率可以大幅度提升的空间在数据库操作部分以及程序控制部分。下面,分条叙述对耗时操作的改进方法。

1.  针对日志记录的优化

关闭日志记录,或者更改日志输出级别。因为从两台服务器的外部系统D上获取到的信息是相同的,所以数据库插入操作会抛出异常,异常信息类似于“Attemptto insert duplicate record”,这样的异常信息跟有效信息的条数相等,有上千条。这种情况是能预料到的,所以可以考虑关闭日志记录,或者不关闭日志记录而是更改日志输出级别,只记录严重级别(severe level)的错误信息,并将此类操作的日志级别调整为警告级别(warning level),这样就不会记录以上异常信息了。本项目使用的是Java 自带的日志记录类,以下配置文件将日志输出级别设置为严重级别。

清单 1. log.properties 设置日志输出级别的片段 

default file output is in user ’ s home directory. levels can be: SEVERE, WARNING, INFO, FINE, FINER, FINEST  java.util.logging.ConsoleHandler.level=SEVERE  java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter  java.util.logging.FileHandler.append=true 

通过上述的优化之后,性能有了大幅度的提升,从原来的 100 秒左右降到了 50 秒左右。为什么仅仅不记录日志就能有如此大幅度的性能提升呢?查阅资料,发现已经有人做了相关的研究与实验。经常听到 Java 程序比 C/C++ 程序慢的言论,但是运行速度慢的真正原因是什么,估计很多人并不清楚。对于 CPU 密集型的程序(即程序中包含大量计算),Java 程序可以达到 C/C++ 程序同等级别的速度,但是对于 I/O 密集型的程序(即程序中包含大量 I/O 操作),Java 程序的速度就远远慢于 C/C++ 程序了,很大程度上是因为 C/C++ 程序能直接访问底层的存储设备。因此,不记录日志而得到大幅度性能提升的原因是,Java 程序的 I/O 操作较慢,是一个很耗时的操作。

2.  针对数据库连接的优化

共享数据库连接。共有 5 次数据库连接操作,每次都需重新建立数据库连接,数据库插入操作完成之后又立即释放了,数据库连接没有被复用。为了做到共享数据库连接,可以通过单例模式 (Singleton Pattern)获得一个相同的数据库连接,每次数据库连接操作都共享这个数据库连接。这里没有使用数据库连接池(Database Connection Pool)是因为在程序只有少量的数据库连接操作,只有在大量并发数据库连接的时候才需要连接池。

清单 2. 共享数据库连接的代码片段 

public class JdbcUtil {  private static Connection con;  // 从配置文件读取连接数据库的信息  private static String driverClassName;  private static String url;  private static String username;  private static String password;  private static String currentSchema;  private static Properties properties = new Properties();  static {  // driverClassName, url, username, password, currentSchema 等从配置文件读取,代码略去  try {  Class.forName(driverClassName);  } catch (ClassNotFoundException e) {  e.printStackTrace();  }  properties.setProperty("user", username);  properties.setProperty("password", password);  properties.setProperty("currentSchema", currentSchema);  try {  con = DriverManager.getConnection(url, properties);  } catch (SQLException e) {  e.printStackTrace();  }  }  private JdbcUtil() {}  // 获得一个单例的、共享的数据库连接  public static Connection getConnection() {  return con;  }  public static void close() throws SQLException {  if (con != null)  con.close();  }  } 

通过上述的优化之后,性能有了小幅度的提升,从 50 秒左右降到了 40 秒左右。共享数据库连接而得到的性能提升的原因是,数据库连接是一个耗时耗资源的操作,需要同远程计算机进行网络通信,建立 TCP 连接,还需要维护连接状态表,建立数据缓冲区。如果共享数据库连接,则只需要进行一次数据库连接操作,省去了多次重新建立数据库连接的时间。

3.  针对插入数据库记录的优化 - 1

使用预编译 SQL。具体做法是使用 java.sql.PreparedStatement 代替 java.sql.Statement 生成 SQL 语句。PreparedStatement 使得数据库预先编译好 SQL 语句,可以传入参数。而 Statement 生成的 SQL 语句在每次提交时,数据库都需进行编译。在执行大量类似的 SQL 语句时,可以使用 PreparedStatement 提高执行效率。使用 PreparedStatement 的另一个好处是不需要拼接 SQL 语句,代码的可读性更强。通过上述的优化之后,性能有了小幅度的提升,从 40 秒左右降到了 30~35 秒左右。

清单 3. 使用 Statement 的代码片段 

// 需要拼接 SQL 语句,执行效率不高,代码可读性不强 StringBuilder sql = new StringBuilder(); sql.append("insert into table1(column1,column2) values('"); sql.append(column1Value); sql.append("','"); sql.append(column2Value); sql.append("');"); Statement st; try {  st = con.createStatement();  st.executeUpdate(sql.toString()); } catch (SQLException e) {  e.printStackTrace(); } 

清单 4. 使用 PreparedStatement 的代码片段 

// 预编译 SQL 语句,执行效率高,可读性强 String sql = “insert into table1(column1,column2) values(?,?)”; PreparedStatement pst = con.prepareStatement(sql); pst.setString(1,column1Value); pst.setString(2,column2Value); pst.execute(); 

4.  针对插入数据库记录的优化 - 2

使用 SQL 批处理。通过 java.sql.PreparedStatement 的 addBatch 方法将 SQL 语句加入到批处理,这样在调用 execute 方法时,就会一次性地执行 SQL 批处理,而不是逐条执行。通过上述的优化之后,性能有了小幅度的提升,从 30~35 秒左右降到了 30 秒左右。

5.  针对多线程的优化

使用多线程实现并发 / 并行。清空数据库表的操作、把从 2 个外部系统 D 取得的数据插入数据库记录的操作,是相互独立的任务,可以给每个任务分配一个线程执行。清空数据库表的操作应该先于数据库插入操作完成,可以通过 java.lang.Thread 类的 join 方法控制线程执行的先后次序。在单核 CPU 时代,操作系统中某一时刻只有一个线程在运行,通过进程 / 线程调度,给每个线程分配一小段执行的时间片,可以实现多个进程 / 线程的并发(concurrent)执行。而在目前的多核多处理器背景下,操作系统中同一时刻可以有多个线程并行(parallel)执行,大大地提高了 计算速度。

清单 5. 使用多线程的代码片段 

Thread t0 = new Thread(new ClearTableTask()); Thread t1 = new Thread(new StoreServersTask(ADDRESS1)); Thread t2 = new Thread(new StoreServersTask(ADDRESS2)); try {  t0.start();  // 执行完清空操作后,再进行后续操作  t0.join();  t1.start();  t2.start();  t1.join();  t2.join(); } catch (InterruptedException e) {  e.printStackTrace(); } // 断开数据库连接 try {  JdbcUtil.close(); } catch (SQLException e) {  e.printStackTrace(); } 

通过上述的优化之后,性能有了大幅度的提升,从 30 秒左右降到了 15 秒以下,10~15 秒之间。使用多线程而得到的性能提升的原因是,系统部署所在的服务器是多核多处理器的,使用多线程,给每个任务分配一个线程执行,可以充分地利用 CPU 计算资源。

笔者试着给每个任务分配两个线程执行,希望能使程序运行得更快,但是事与愿违,此时程序运行的时间反而比每个任务分配一个线程执行的慢,大约 20 秒。笔者推测,这是因为线程较多(相对于 CPU 的内核数),使得 CPU 忙于线程的上下文切换,过多的线程上下文切换使得程序的性能反而不如之前。因此,要根据实际的硬件环境,给任务分配适量的线程执行。

6.  针对设计模式的优化

使用 DAO 模式抽象出数据访问层。原来的代码中混杂着 JDBC 操作数据库的代码,代码结构显得十分凌乱。使用 DAO 模式(Data Access Object Pattern)可以抽象出数据访问层,这样使得程序可以独立于不同的数据库,即便访问数据库的代码发生了改变,上层调用数据访问的代码无需改变。并且程 序员可以摆脱单调繁琐的数据库代码的编写,专注于业务逻辑层面的代码的开发。通过上述的优化之后,性能并未有提升,但是代码的可读性、可扩展性大大地提高 了。

清单 6. 使用 DAO 模式的代码片段 

 // DeviceDAO.java,定义了 DAO 抽象,上层的业务逻辑代码引用该接口,面向接口编程 public interface DeviceDAO {     public void add(Device device);  }  // DeviceDAOImpl.java,DAO 实现,具体的 SQL 语句和数据库操作由该类实现 public class DeviceDAOImpl implements DeviceDAO {     private Connection con;     public DeviceDAOImpl() {         // 获得数据库连接,代码略去    }  @Override  public void add(Device device) {         // 使用 PreparedStatement 进行数据库插入记录操作,代码略去    }  } 

回顾以上代码优化过程:关闭日志记录、共享数据库连接、使用预编译 SQL、使用 SQL 批处理、使用多线程实现并发 / 并行、使用 DAO 模式抽象出数据访问层,程序运行时间从最初的 100 秒左右降低到 15 秒以下,在性能上得到了很大的提升,同时也具有了更好的可读性和可扩展性。 

四、结束语

通过该项目实例,笔者深深地感到,想要写出一个性能优化、可读性可扩展性强的程序,需要对计算机系统的基本概念、原理,编程语言的特性,软件系统 架构设计都有较深入的理解。“纸上得来终觉浅,绝知此事要躬行”,想要将这些基本理论、编程技巧融会贯通,还需要不断地实践,并总结心得体会。 

英文出自:IBM DeveloperWorks

从MySQL迁移到MariaSQL Wikipedia力求开放 奥巴马筹款网站的制作过程 国内芯片厂商发力4G 新岸线2013年将推LTE方案 CMDN Club 23期:开放平台和O2O移动产品开发 花旗调低Apple股票评级 不信iPhone5会卖得好 2012年Linux Journal读者选择奖结果公布 百度云SiteApp:三步轻松创建移动网站 Twitter跨数据中心图片存储系统Blobstore解析 摩托罗拉携手中国移动发布Intel Inside智能机新锋丽i MT788 第五届“英特尔杯”全国大学生软件创新大赛圆满落幕 Appro推出液冷超级计算机 Dell:曾敦促微软WinRT放弃Windows品牌 IE10十大优点:渲染页面比Chrome快8% 法国电信:开放平台下的O2O移动产品怎么玩? 客如云创始人彭雷:寻找O2O“失落的半圆” 中国电信宋鹏飞:天翼开放平台的服务及架构解析 W3C小组宣布:HTML5标准制定完成 还记得DUQU吗?起因可能是Windows中存在了20多年的漏洞! API管理的五大规则 Google也节能:挖角美能源部Arun Majumdar博士 预测:云计算领域的5大变革 CTO俱乐部:移动信息化的创新实践及互联网创业 核心组图曝光:BlackBerry 10明年1月30日发布 “蛐蛐儿”创始人朱连兴:音频二维码的技术实现和应用场景 信恩科技创始人林兴陆:QR Code二维码的前世今生 2012移动开发工具盘点:傻瓜式游戏工具引擎 《福布斯》发布年度“未来之星” 扎克伯格上榜 Cloudera透露Impala发行版新功能及开源计划 Nokia落寞身影下 三星成为全球最大手机厂商 乐视网CTO:智能电视,一个诱人的议题 SeatGeek:Web设计师如何转型iOS开发? 谁有生成TIN三角网的代码? Tlink怎么用? 如何打印recordset对象 bcb编译工程需要做的设置都有什么呀! 又有问题了!TStringList的一些冲突? 我的WIN2000各个盘都被共享, 却不显示共享的手型图标 !!!!!!! 如何定制列表视(report style,full Row Select)的高亮选中条的字符和背景颜色? 表名作为参数问题? VFP两个表的纵向合并? 机器突然掉电是怎么回事? 请教高手,怎样对TreeView控件的节点的OnClick事件处理? 一条出错信息的意思???? 怎样在dreamweaver里面插入包含网页??? 好久没为这样的小事快乐了 紧急求教(关于控件打包问题) 怎么开发互联网和手机短信互通的软件? 哪位有<<游戏编程大师技巧>>的原码 求一简单程序 installshield for c++builder:怎么把客户‘安装路径’注册到他的注册表里-现在急用 请问这4个组件在那个组件拦上的 TFileListBox,TDirectoryListBox,TFilterComboBox,TDriveComboBox 一条出错信息的意思??? ManagermentServer为什么启动不起来?? CList的RemoveAt()问题 爽!今天买了一个可无线上网的手提,散分! 本人用insertShile安裝制作軟件制作了vb6的一個setup文件包,直接用硬盤copy到其機子安裝是沒問題的,但是本人將該setup文件包刻錄到光盤 如何可以将windows 2000 server的C、D等盘的默认共享属性去除,可不可以将这个属性永久去除,因为选择“右击”-“共享”去除后,重启又出 如何让你的编译器生成汇编代码 怎么样把数据库里的某个字段读到ComboBox1里? 在MDI框架中,如何禁止View相互切换? 代码转换 谁能告诉我delphi6.0中的installshield怎样使 为什么我用Zend Encoder加密了一个php文件,速度比以前没加密慢了好多哦, 怎样让在运行时加载的控件总在最前面?? 代码转换 linux + mysql+ apache + php + jdk + jsdk 怎样让在运行时加载的控件总在最前面?? 代码转换 一个关于全局变量的访问问题。 263游戏大厅里的用户信息列表是怎么实现的?急问,多谢!! 也帮帮我吧!i'll be dead ! 263游戏大厅里的用户信息列表是怎么实现的?急问,多谢!! 关于窗体 如何去掉我的“计划任务”共享? linux + mysql + apache + php + jdk + jsdk 新手问各位大哥一个问题:我在机器上已经安装了98,2000,现在有装了红帽7.2,已经安装成功,但是在LOGIN之后,有开始GNOME之后,什么都 菜鸟问题,请多帮忙 window 2000 server服务器,不能使用mail函数,怎么解决!?急!! 我靠!我今天算碰到一个希奇事!你们听听这个网址! 关于鼠标右键菜单的制作问题 SOS!100分相送。很简单的题目,明天考试急用 请问oracle中的帮助导航器、帮助主题窗口是在哪里啊 英语翻译many customers found that they were not receiving the nondestructive test examinations they felt they had paid to receive.具体些,英语不好,正在学习,顺便告诉一下我下次遇到这种语句如何翻译. 谁知道关于TIME 的所有的短语 告诉我 谢了! Lily needs___sports,she isn`t healthy.A does B: to do C:doing D:to does As long as you hold my hand.I'll go along withAs long as you hold my hand.I'll go along with you.第一个回答正确采纳 Don't worry.We still have ______ little time left.怎么填写 为什么 They saw a man _____ along the road.A.walking B.walk C.walks 英语同义句转换I found that they were good.I found them ___ ___ good同义句转换,每空一次I found that they were good.I found them ___ ___ good. Don’t worry about the time.We still have _______days left.a.another 3 b.3 another c.3 others d.other three 选哪个?为什么?解释下他们的差别和用法. 好书推荐(一本就够了) 1.书名 2.作者 3.主要内容 4.主要人物介绍 5.喜欢的原因注意:主要内容只要100~300不要太多,人物每个50~100字就好. As long as you hold my hand .I well go along with Don't worry we still have time to do the job A fell in love with B falls in love with C D my mother ( ) tired after she does some housework .括号里填什么 They were waiting for a train that was very late.帮我吧这个句子翻译, 让我看看你的照片,好吗的英文may l take [ ] [ ] [ ] your photos? 12岁女孩到哪去做明星报名 They all said that Italians were very strange people b__翻译和填空 '这个照片限时观看"英文怎么翻啊 Does the man ____(want) to clean his car?用括号里的词的适当形式填空,谢谢 It has been raining ______ last Saturday.A:on B:for C:till D:since His grandma is eighty.she is very o 张杰唱的just the way you are 为什么那么难听发音就不说了,感觉咋那么土呢,好难听啊 the plane l____safely at last though it was raining hard my grandma is very old now,but she was a teacher before (同义句)my grandma___ ____be a teacher before,but now she is very old I want you to always live in my heart,even if separated as we like together!请牛人翻译一下 做梦 梦到很多蝴蝶 同上 6."Where does he live?" Mr Hu asked.(改为复合句) Mr Hu asked where ______6“Where does he live?”Mr Hu asked.(改为复合句) Mr Hu asked where _______ _______.7.Tom’s father saw him sitting on some eggs.(改为复合句) Tom’s father saw ( )The old man _______ to take medicines.He's already fine A.needn't B.need C.doesn't need D.needs not 绞丝旁加个色字念什么?谢谢了,大神帮忙啊 ''Where does Lily live?''(改为复合句)I wonder ___ ___ ___. The old man ____ go out for a walk twice a week.A.need B.needs C.needs to D.both A and BI______(希望) i could go to the country in the USA.The old man ____ go out for a walk twice a week.A.need B.needs C.needs to D.both A and B 绞丝旁加一个寅字是什么字啊? What time do you get to school and how many classes do you have这句话的意思 _________ I need to take the medicine?根据内容填空. 一个绞丝旁一个真是什么字?书上写的是shěn我打不出来 3本书的书名和主要内容 主要内容要少一点 大约20个字 different名词 collect名词 sell反义词 happy名词 stand过去式 busy反义词 careful副词 skip现在分词 base on和because of的近义词分别是什么,四个词的 一些网友发的英文照片评语,手工翻you are really living beauty of ur own.hats off dear. 英文短信件手工翻中2yeah,baby,do not have stress after sleeping...what are you going to study?this is nice to study sometimes...i watch new harry potter,do you know it?so i am going to sleep,will try...will see your beautiful smile and will s -Do you think it will be cool tomorrow?-,_.It has been too hot for a week.A.I hope so B.I'm afraid so C.So it is D.Of course not我选的是A,但答案给的是C,请问谁能解释清楚? 照片的2英文短评语翻中人工的This is erotically sexy!You look delicious!A hot sexy ninja in a dress.>. 英语好的帮我翻译一下,hey.i was goin' over here,and I came across ur place.U appear to be Do you think it will still be rainy tomorrow?____It has rained for many days.A.I hope not B.I'm sure it will. old man has the years for word twenty here连词成句 英文短信件手工翻中hi my dear!))your last pics are very sweet!i even haven't words to say my feeling)so cutie and ideal)Asia is so big...yeah translater is not very good,i know it,that's why i asked your language,i can learn it hard and speak grandma is 70years old.My grandma is__70 years old,but she looks young she like to be beautiful..she doesn't ( ) the idea that old people can't be beautiful We've lived here for ten years?对for ten years提问. the great wall wind it way over high mountains ,through deep valleys and across grest deserts如何翻译 she is _____15 years old means she is 15 years old.A not more than B not less than C no more thanD no less than 这四个答案选什么 能不能帮我翻一下下面图的英文什么意思! 英文短信件翻中手工的HI!i saw a message on my wall from you and now i feel really worried!you wrote that i speak with other girls at the same time that maybe i do not like you...this is absolutelly fake!why do you think so?as you can see my 宾语从句例句1.Polly says:“I want to eat an apple”.2.It’s very clod in Moscow.He said3.where does Mr Li live?Do you know.4.We had a football match.Tom said.5.Listen to me carefully.The teacher told me .6.Whose jacket is this Can you tell 1 Miss Liu is very busy.—______. A. She does so B. So she does C. So does she D. So she is2 -How much _____ the sneakers? ----Tendollars ______ enough. A. is; is B. are ; is C. are ; are D. is ; is 3-That T-shirt with YaoMing’s pictur She 's very busy.She has a lot __.A do B does C doing D to do为什么是D啊,看不出是做定语啊 As long as you hold my hand,I'll go along with you. “辑”这个字,把车字旁换成绞丝旁,怎么念, she has a lot of things ____.A.do B.does C.doing D.to do As long as you hold my hand ,I'll go along with you , 求最佳翻译、 有关time的短语(它们的用法,意思.等) Once a rich man was walking along the road with his servant.Suddenly,a young man carrying a heavy bag passed by him.
备案号:鲁ICP备13029499号-2 说三道四 www.s3d4.cn 说三道四技术文摘