java深度-----effective java,
分享于 点击 40370 次 点评:114
java深度-----effective java,
[code]高性能java
1.开发高性能java程序的原则与方法
优化程序代码的注意事项:
1。除非必须优化,否则不要轻易改动
2。改动之后要进行仔细的测试
3。在各个JVM产品中是不存在一劳永逸的成本模型
(在某个虚拟机上做的优化效果非常好,但是到了别的虚拟机上就不一定重现了)
2。先把焦点放在设计,数据结构和算法上
每一个方法不应该长,可以方法里面引入方法,这样jit所做的工作就会少
1。使用StringBuffer来做拼接
因为如果用String,那么很多对象将在Eden区域产生,很可能在此时造成垃圾全收集的产生
StringBuffer b = new StringBuffer("a"); //这里只产生一个对象,因为他会把a这个二进
制的东西(注意这时还不是一个对象),加到b这个对象里面,所以只有一个对象。
注意:"a"有两种身份,第一种身份是对象,第二种身份是和int这中东西一样的基础类型
所以使用StringBuffer来操作字符串拼接,那么从始至终都只有一个对象哈,虽然在传值给
append的时候传递了"a"这种东西,但是这个时候他不是一个对象
2。javap -c Test 可以生成字节码文件
通过字节码我们知道加入同步控制会导致字节码指令体积会增加
同步方法获取的是对象锁
Class Test{
public synchronized void m1(){
}
public synchronized void m2(){
}
public synchronized void m3(){
}
public synchronized void m4(){
}
}
//注意啦,这四个方法居然用了同一把锁,就是这个对象锁(this),
那么第一:四个方法只能由一个方法在一个时间内使用
第二:如果方法里面有全局变量,对象所还没有用,因为别的线程很可能
new一个自己的对象,还是可以进入这个方法来
所以千万不要使用方法同步
我们一般用字节数组作为锁变量
class Test{
private byte[] lock1 = new byte[0]; //技巧哈
private byte[] lock2 = new byte[0];
public void m1(){
synchronized(lock1){
//======================
}
}
}
尽量使用stack变量和基本类型完成必要的任务
一个方法的局部变量会存放在这个方法的运行时栈当中
stackAccess方法性能要高于staticAccess以及instacevarAccess
staticAccess和instacevarAccess方法的性能大体一致,因为他们都是从常量池中去得到实例变量
所以尽可能的使用局部变量
class StackVar{
private int instvar;
private static int staticvar;
void stackAccess(int val){
int j=0;
for(int i=0;i<val;i++){
j +=1; //这是对局部变量++
}
}
void instacevarAccess(int val){
//每次都要访问常量池,性能有问题,第二并发有问题
for(int i=0;i<val;i++){
instvar += 1; //这是对实例变量++
}
}
void instacevarAccessPer(int val){
int j= instvar;
for(int i=0;i<val;i++){
j+=1;
}
instvar = j;
}
void staticAccess(int val){
for(int i=0;i<val;i++){
staticvar += 1; //对静态变量++
}
}
void staticAccessPer(int val){
//性能不错,只需要访问两次常量池,
//其他操作都是在本地栈中完成的
int j=staticvar;
for(int i=0;i<val;i++){
j+=1; //对局部变量++然后赋值给静态变量
}
staticvar = j;
}
}
使用static final private 函数以促成inlining
内联函数会使用函数的代码来替换函数的调用,将函数的代码原封不动的
拷贝到调用处,省去了函数调用的消耗,以促使性能的提升,但是如果你将一个
函数声明为static final private那么java编译器就会把这种函数作为inlining
的候选者,为什么是候选者呢?因为如果你的函数写的非常大的话,那么他会使得你函数的体积
发生激增,所以Java编译器会先看下代码的长度,代码太长他也不会把他变为内陆函数的
实例变量初始化一次就好
如果你new一个类,那么java虚拟机如何对他初始化
1。在堆中分配内存
2。对实例变量进行缺省值的初始化
3。执行构造方法的赋值动作
但是如果我们private int count=1;这么搞则有四步
1。在堆中分配内存
2。对实例变量进行缺省值的初始化
3。覆盖缺省值
4。执行构造方法的赋值动作
或者有初始化区段,比如static{}
那么
1。在堆中分配内存
2。对实例变量进行缺省值的初始化
3。初始化区段---这个虽然是static的,但确是在实例变量缺省值初始化之后
4。执行构造方法的赋值动作
class Foo{
private int count; //private int count=1;这样也会被执行两次,先执行缺省值赋值,
private boolean done;
private Point pt;
private Vector ver;
public Foo(){
count = 0; //这个东西被初始化了两次哈
done = false; //他的缺省值本来就是false,他又初始化一次
pt = new Point(0,0);
vec = new Vector(10);
}
}
class Foo{
private int count;
private boolean done;
private Point pt;
private Vector ver;
public Foo(){
pt = new Point(0,0);
vec = new Vector(10);
}
}
集群类对象的处理
1.数组,HashTable,Vector,Stack等数据结构类用于容纳和处理对象
注意:Collection类里面放的都是对象哈。。简单类型也会自动转型才被放入
1。权衡使用迭代器:Iterator,ListIterator,Enumeration
class AccessCollection{
public int enumCec(Vector vec){ //比较快,比后面的快10%
Enumeration enum = ver.elements();
int toral = 0;
while(enum.hasMoreElements()){ //在这里访问了一次容器,就比forVec慢了
total = ((Integer))(enum.nextElement()).iniValue();
}
return total;
}
public int iterVec(Vector vec){
Iterator it = vec.iterator();
int total = 0;
while(it.hasNext()){
total +=((Integer))(it.next()).iniValue();
}
return total;
}
public int listiterVec(Vector vec){
ListIterator it = vec.listIterator();
int total = 0;
while(it.hasNext()){
total +=((Integer))(it.next()).iniValue();
}
return total;
}
public int forVec(Vector vec){//最快,比前三个方法快35%
int size = vec.size();
int total = 0;
for(int i=0;i<size;i++){
total +=((Integer)vec.get()).intValue();
}
}
}
如何复制数组元素:
使用循环复制;---不好
使用System.arraycopy()方法---好,比循环复制快两倍,
因为他采用操作系统底层的复制,而不是采用循环的方式
System.arraycopy(src,0,des,0,src.length);
从原数组第0个元素开始拷贝,拷贝的长度为src.length;
把他拷贝到des时,以第0个位置作为起始元素
优先数组,然后考虑群积类,尤其是在性能优先的需求中;
如果需要群集类功能,但又不考虑同步,可以先选择非同步的集群类如ArrayList;
如果需要集群类功能,又要顾及到数据同步保护时,可以选择同步集群类,如Vector;
如果选择集群类,要分清集群类使用的目的
注意:不要因为有个个数无法确定的数据需要存储,就毫无选择的使用集群类,出现这种情况可以考虑创建一个足以
容纳大量数据的array,这可能造成内存浪费,但是在性能上往往会获得更大的收益
[/code]
相关文章
- 暂无相关文章
用户点评