Run Faster-JAVA
又好久没有写点啥了,平时都忙于工作,忙于应付工作中的问题,各种吸收却并没有好好的消化,该是"反刍"一下的时候了。
本篇名叫"Run
Faster,JAVA",其实JAVA发展到现阶段,无论是编译器优化还是运行时优化,都做的很好了,速度早已不像过去那样被人诟病,本篇只是自己日常工作的一些总结,很不全面,但是都是很实际且能立竿见影的,可以当低层次技术文章看看,当然最好能在实际的开发中尝试尝试。(PS:为照顾大家看技术文章容易犯怵的情绪,采用快餐式的讲解,不深入,不解释,只求精神上的共鸣,不喜欢技术的就当“杀马特"随便瞄一眼吧。。。)
常见的JAVA应用下容易出现瓶颈的因素:磁盘I/O,网络操作,CPU,数据库读写,应用单多线程,多线程锁竞争,JAVA GC等。针对这几个因素,一般的调优层次是: 设计调优--->代码调优--->JVM参数调优--->数据库调优--->OS调优,当实际应用出现瓶颈需要调优时,一般的步骤是:代码--->JVM参数--->数据库--->OS--->应用架构(设计),可以看到,首先需要调优的就是代码,那么我们今天先讲讲代码调优的一些口诀:
1:多用设计模式(主要是单例,享元,观察者,访问者,装饰者,代理等),如果你写了两年以上代码,还没用过常见的模式,我只能说,赶紧洗洗换行当吧。学习设计模式我推荐<<Head First 设计模式>>一书,轻轻松松看下来,找几个例子熟悉,关键是平常开发中有意识的培养自己去实现,每个模式写一两个例子就都了然于胸了。至于外界盛赞的GOF<<设计模式>>,建议当常备参考书放到书桌旁有需要时参考就行了。
2:Buffer/Cache,缓冲/缓存思想,这个应该很容易理解。Buffer是说take it easy,slow down.而Cache则是说take it ,you'll
user it someday.
3:多线程并行代替串行(要求一般串行间没有因果或前后关系),说白了就是用多线程替代单线程,充分利用CPU资源,当然很多在单线程下能正常执行的程序在多线程下可能会出现问题,用锁固然可以减少线程冲突,但是锁太多反正抑制了多线程的威力,而且容易出现锁等待,死锁等问题。尽管如此,多线程替代单线程可以大幅提高效率,尽量使用。
4:应用负载均衡(JVM级,需要处理好共享数据的一致性问题),如果应用将来做负载,那么在编写代码的时候就要考虑共享数据的一致性,共享缓存听起来是一个很诱人的东西,可是真正实现的时候会有很大的麻烦,别说你已经很熟悉MappedByteBuffer +
RandomAccessFile,too simple。
5:时间/空间的转换,缓存是这种转换的一种实现,当然还有生产者-消费者模式,如果你来不及计算所有的任务,花点内存先保存这些任务,然后启用线程慢慢计算。还有在循环中存储中间临时结果以备后续调用也算。
6:使用ValueObject减少计算或请求次数,将请求封装到一起,尽量一次请求就把需要的参数给全,得到所有想要的结果。多次请求总是会耗损资源的,无论是HTTP,TCP还是普通方法调用请求。
口诀说完了接下来就是招式了,优化的最高境界当然是无招胜有招,不过还得从简单的招式练起,这次先学下面几招入门级的:
0):不要在循环体里定义引用并创建对象,将定义引用放到外面
Object
obj = null;
for (int i = 0; i < 10000; ++i) {
(Object) obj = new Object();
System.out.println("obj= "+ obj);
}
1):避免重复初始化对象
public class A {
private Hashtable table = new Hashtable
(); //这个问题一般开发人员都会碰到吧
public A() {
table = new Hashtable(); // 将Hashtable对象table初始化了两次
}
}
2):字符串优化的几个地方
a:substring()方法速度很快,但是容易引起内存溢出问题,因为会保留对原串的引用,所以建议用new String(***.substring(参数))的模式
b:对字符串截取可用split,split内部调用的Pattern.complie.split,因此如果拆分规则比较复杂,每次Pattern.complie的时候会有损耗,可以考虑将Pattern.complie静态化然后直接调用split,这样只需要complie一次即可。当然还想速度快点的可以考虑StringTokenizer(sun不建议使用),想最快的可用indexOf+substring自己实现截取
c:对字符串的开头/结尾子串判断一般用startsWith/endsWith,由于他们和split一样是基于正则的,会有上面说过的问题。所以最好用charAt来自己实现更快
d:对字符串的相加,StringBuild最优,StringBuffer次之(线程安全),String.concat再次之,+/+=最次(此处不考虑静态常量编译器的优化)
3):ArrayList(Vector)与LinkedList比较
a:ArrayList基于数组(一块连续的内存空间),LinkedList基于双向链表,因此ArrayList的主要性能耗在扩展空间时数据复制,而LinkedList耗在数据遍历(尤其是找中间的数据)
b:头尾的新增/删除对LinkedList没有压力,但是每次随机访问需要从头查找,会要亲命
c:在尾部添加对ArrayList没有压力,但从头部删除都会数组复制,会要亲命。
d:对LinkedList的遍历,要么用for-Each,要么Iterator,不要用普通的ini
i=0;i<size;i++,因为get(i)是随机查找,每次都从头或尾遍历,会要亲命
e:一般实现了RandomAccess接口的类如ArrayList,Vector才可以在遍历时放心使用get,而且遍历时要尽量减少重复的获取size或元素,用临时变量缓存之
4):HashMap如果key是一个个重写了hashCode方法的对象,如果此hashCode方法放回相同的int值,则每次放入不同对象会到同一个桶下,同一桶下是用链表组织数据的,如果查找需要遍历链表,会要亲命。
5):HashMap底层用了数组实现,使用大于等于initialCapacity并且是2的指数次幂作为数组大小,threshold为当前数组总容量与负载因子的乘积,即阀值,当实际容量超阀值 时会进行数组扩展复制,而复制会消耗CPU资源,因此适当的initialCapacity有利于提高性能。另外别忘了HashMap在多线程下并发put会有导致CPU满负荷的bug。
6):LinkedHashMap基于元素进入顺序或被访问先后顺序(被访问的元素放到最后),而TreeMap基于传入的Comparetor参数或实现了Comparable的key对象进行排序,适用范围 不一样,前者可以用来实现LRU算法,后者在一致性Hash上大有作用。而HashSet,LinkedHashSet,TreeSet是对应Map的简单封装。
7):使用NIO(ByteBuffer+Channel)可以提升I/O读写速率,注意duplicate(),asReadOnlyBuffer(),slice()都是共享原始缓存数据的,一般用文件内存映射MappedByteBuffer,结构 化散射接口ScatteringByteChannel,结构化聚集接口GatheringByteChannel将多个ByteBuffer组成一个数组一次写入,用DirectBuffer代替ByteBuffer进行多次读写都可以提高效 率,但DirectBuffer是直接开辟OS内存,如果频繁新建回收,性能反而不如ByteBuffer虚拟机内的相同操作.
8):4个引用级别:强,软,弱,虚,其作用分别不同,一般软和弱引用可以作为缓存的一种方案避免内存溢出,而虚更多用于跟踪对象回收时机,弱引用WeakHashMap可以 作为简单的缓存对象。
9):不在循环代码中使用try-catch,尽量放到循环体外,多用局部变量或临时变量存储计算值以避免重复计算,可以考虑在一次循环中做多个操作减少循环次数(i+1,i+2,i+3...),多 用"阻断性"逻辑运算如&&来代替位运算如&(当然一般也不建议利用条件判断来做一些操作,因为后面的判断默认应该可以不去运行的)
10):多用一维数组代替二维数组;使用Buffer进行I/O;对构造成本大的函数,用clone代替new(注意该类实现Cloneable,并且默认是浅复制,深复制需要自己重写Object的clone 方法)
12):技巧:用位运算代替2次幂的乘除;
13): 多用static静态方法而不是实例方法
14): 多用native方法如arrayCopy等;
to be continued…..
Run Faster-JAVA的更多相关文章
- SpringCloud异常(Euruka):Application run failed java.lang.NoSuchMethodError: org.springframework.boot.builder.SpringApplicationBuilder
在测试Euruka作为服务注册中心的时候碰到了这个问题,错误提示如下: "C:\Program Files\Java\jdk1.8.0_161\bin\java" -XX:Tier ...
- 解决Run As -> Java Application不能运行问题
转自:https://breakshell.iteye.com/blog/467130 点 Run As -> Java Application 不能运行,报的错误如下: Plug-in org ...
- 线上zk节点报org.apache.zookeeper.server.NIOServerCnxnFactory.run(NIOServerCnxnFactory.java:187) at java.lang.Thread.run(libgcj.so.10)
线上zk做配置管理,最近突然发现两个节点一直在刷下边 java.nio.channels.CancelledKeyException at gnu.java.nio.SelectionKeyIm ...
- spring boot: 热部署(一) run as – java application (spring-loader-1.2.4.RELEASE.jar)
spring boot: 热部署(一) run as – java application (spring-loader-1.2.4.RELEASE.jar) 如果使用的run as – java a ...
- win10+eclipse+hadoop2.7.2+maven+local模式直接通过Run as Java Application运行wordcount
一.准备工作 (1)Hadoop2.7.2 在linux部署完毕,成功启动dfs和yarn,通过jps查看,进程都存在 (2)安装maven 二.最终效果 在windows系统中,直接通过Run as ...
- 5 Ways to Make Your Hive Queries Run Faster
5 Ways to Make Your Hive Queries Run Faster Technique #1: Use Tez Hive can use the Apache Tez execu ...
- eclipse中的项目运行时不出现run as→java application选项
eclipse中的运行java project时不出现run as→java application选项? 解决方案☞必须有正确的主方法,即public static void main(String ...
- Eclipse中run as run on server和run as java application
一.run java application (作为Java应用程序运行)是运行 java main方法 run on server是启动一个web 应用服务器 二.两者的区别: Eclipse中 ...
- maven project中,在main方法上右键Run as Java Application时,提示错误:找不到或无法加载主类XXX.XXXX.XXX
新建了一个maven project项目,经过一大堆的修改操作之后,突然发现在main方法上右键运行时,竟然提示:错误:找不到或无法加载主类xxx.xxx.xxx可能原因1.eclipse出问题了,在 ...
- 通过crontab调度java -jar任务提示"nohup: failed to run command `java': No such file or directory"
通过crontab无法运行,提示如标题的信息: 但直接在终端控制台执行sh和java -jar都可以: 网上给的提示解决方法,在.sh文件开始上面加上 source /etc/profile 然后cr ...
随机推荐
- hdu3999-The order of a Tree (二叉树的先序遍历)
http://acm.hdu.edu.cn/showproblem.php?pid=3999 The order of a Tree Time Limit: 2000/1000 MS (Java/Ot ...
- TP3.1 一对多模型关联
TP3.1.3 的一对多的模型关联 老需求 --- 一个用户多个文章,查看这些文章 HasMany 首先定义Model 模型名字叫UserMode.class.php class UserMode ...
- Qt Setting Application Icon
Qt4 设置应用程序图标 将一个ico图标放在资源文件夹下; 然后建立txt,输入 IDI_ICON1 DISCARABLE "myico.ico"; 保存文件,将其后缀改为.rc ...
- UEFI下win10+Ubuntu双启动后完全纯净卸载Ubuntu,重建BCD
以下内容操作具有风险,操作前请提前备份数据.建议由有丰富经验的人使用,需要掌握diskpart. 背景 使用ubuntu+win10 dual boot后,需要重置回纯净win10系统. BCD是Bo ...
- AlwaysOn的数据同步原理
摘抄自<SQL Server 2012实施与管理实战指南> 镜像的工作原理: 那么主体数据库和镜像数据库是如何同步数据的呢?SQL数据库中任何的数据变化都会先记录到事务日志中,然后才会真正 ...
- ecshop后台登录频繁自动退出问题终极解决方法集锦
ecshop后台登录后,有时候会自动退出,而且还会很频繁,有的是后台操作两下就莫名退出了,有的是恰好三分钟左右登出.这让管理员很恼火,严重影响了后台使用.对于这一问题,网络上可给的解决方法各有不同.千 ...
- 全面剖析Smarty缓存机制二[清除缓存方法]
前段时间,写了一篇 Smaryt缓存机制的几种缓存方式 ,详细介绍了三种缓存方式:全局缓存.部分缓存.局部缓存,以及通过is_cache()判断是否存在缓存来进行缓存生成.本来这篇早该完成,由于时间关 ...
- element onclick 动态创建元素并绑定onclick事件
<html> <head> <meta charset="UTF-8"> <title>b</title> <sc ...
- iBeacon的第一篇(基于Swift实现)
低功耗蓝牙技术现在几乎是只能手机的标配.随着这一技术的发展,苹果在2013年WWDC大会上,苹果推出iBeacon技术.该技术允许开发人员开发能够使用iBeacon硬件传感器的iOS应用程序,来为相应 ...
- sql 两大类 DDL数据定义语言 和DCL数据控制语言
SQL分为五大类: DDL:数据定义语言 DCL:数据控制语言 DML:数据的操纵语言 DTL:数据事务语言 DQL:数据查询语言. DDL (date definition lang ...