`

Java高效代码举例

    博客分类:
  • java
 
阅读更多
for循环一次的时间耗费在5个单位左右,本地int变量赋值一次的时间耗费在1-2个单位。下表列出了各种操作的时间耗费:
操作 时间耗费
int var = var 1.5
int array[0] = array[0] 4
for 6
throw --- catch 5000

下表是各种类型之间转化的时间耗费:
转化形式 时耗
SubClass = (SubClass) SuperClass 4
Interface = (Interface) Class 4
int à byte, intà char, intà short, intà long 1
intàfloat, intàdouble 3
intß long 10-15
intß float, intß double 15-20
longß float, longß double 30-40

以上时间消耗是个参考。

尽量使用局部变量
下面给出一段代码示例,对比后说明怎么尽可能地使用stack变量:
public class StackVars {
private int x; // instance变量
private static int staticX; //static 变量
public void stackAccess(int val) { //访问和操作stack变量j
int j = 0;
for (int i = 0; i < val; i++) {
j += 1;
}
}
public void instanceAccess(int val) {//访问和操作instance变量x
for (int i = 0; i < val; i++) {
x += 1;
}
}
public void staticAccess(int val) {//访问和操作static变量staticX
for (int i = 0; i < val; i++) {
staticX += 1;
}
}
}
经测试,发现运行instanceAccess()和staticAccess()方法的时间大约相同,但却比运行stackAccess()方法慢了2~3倍。因此我们对instanceAccess()、staticAccess()两个方法的代码作以下调整,以得到更快的性能:
public void instanceAccess(int val) {//访问和操作instance变量x
int tempX = x;
for (int i = 0; i < val; i++) {
tempX += 1;
}
x = tempX;
}
public void staticAccess(int val) {//访问和操作static变量staticX
int tempStaticX = staticX;
for (int i = 0; i < val; i++) {
tempStaticX += 1;
}
staticX = tempStaticX;
}
改善之处就是将instance和static变量放到循环之外,而用一个stack变量来完成多次局部运算,最后再将这个stack变量的值传回instance或static变量,从而提高了代码的性能。

注意对象的创建
String 是不可变的对象,因此在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象,所以经常改变内容的字符串最好不要用 String ,因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以后, JVM 的 GC 就会开始工作,那速度是一定会相当慢的。
例子1:
String conditions = "GROUPNO = '" + groupNo + "' AND TABLENAME = '" + tableName + "'";

改成
StringBuffer buff = new StringBuffer();
buff.append("GROUPNO = '");
buff.append(groupNo);
buff.append("' AND TABLENAME = '");
buff.append(tableName)
buff.append("'");


在循环体中注意对象的创建,尽量少创建新对象,以下data对象其实可以只创建一次。
例子2:
int len = 0;
FileInputStream fis = new FileInputStream("tt.data");
try{
while( len!=-1 ){
byte[] data = new byte[1024];
len = fis.read(data);
//...
}
}finally{
fis.close();
}
改成
int len = 0;
byte[] data = new byte[1024];
FileInputStream fis = new FileInputStream("tt.data");
try{
while( (len = fis.read(data))!=-1 ){
//...
}
}finally{
fis.close();
}


避免没必要的new,比如定义了个变量来引用已有的对象,那么这个定义的变量就不需要new。
例子3:
List<WbusinessCmain> wbusinessCmainClaimCancelList = new ArrayList<WbusinessCmain>(
0);
wbusinessCmainClaimCancelList = bpmCommonService
.getAllByBusinessNo(prpLclaim.getClaimNo(),
ClaimNode.REJECTUNDWRT.getNodeName());

改成
List<WbusinessCmain> wbusinessCmainClaimCancelList = null;
wbusinessCmainClaimCancelList = bpmCommonService
.getAllByBusinessNo(prpLclaim.getClaimNo(),
ClaimNode.REJECTUNDWRT.getNodeName());




循环条件中不用复杂表达式
在不做编译优化的情况下,在循环中,循环条件会被反复计算,如果不使用复杂表达式,而使循环条件值不变的话,程序将会运行的更快。

例子:
for (int i = 0; i < vector.size (); i++){
//...
}

改成:
int size = vector.size ();
for (int i = 0; i < size; i++){
//...
}


释放资源
及时释放资源和保证资源释放,及时释放资源一般在一个方法中使用和释放资源。
例子1:
public static Properties loadProperties(String fileName)
        throws IOException {
    FileInputStream stream = new FileInputStream(fileName);
    try {
        Properties props = new Properties();
        props.load(stream);
        return props;
    }
    finally {
        stream.close();
    }
}
这个方法是用了FileInputStream资源,并在方法结束时调用 stream.close(); 释放了该资源。

保证释放资源,就是当你同时打开多个资源时,要保证每个资源都能释放掉。
例子2:
public void () throws SQLException {

    Connection connOra = null;
    Connection connDb2 = null;
   
    try {
        connOra = getConnection("ora");
        connDb2 = getConnection("db2");
        // Use connection
    }
    finally {
        try {
            if (connOra != null) {
                connOra.close();
            }
        }
        finally {
            if (connDb2 != null) {
             connDb2.close();
            }
        }
    }
}
以上例子保证了,不管出现什么异常,connOra和connDb2的close方法都能执行到。


缩短有限资源的占用时间
比如数据库连接,我们在分配到连接后,尽量只做数据存取操作,并且尽可能减少操作次数。
比如:
int len = vec.size();
for(int i=0;i<len;i++){
conn.executeUpdate((String)vec.get(i));
}
String sql = endNode(node);
conn.executeUpdate(sql);
这段代码存在的问题:
循环执行sql语句;
执行了endNode业务方法;
正确的做法是把endNode方法放到获取连接前,把执行sql做成批量几次执行完(最好1次,但考虑到可能批量有长度限制)。


死锁例子
死锁产生的原因很简单。线程1锁住资源A等待资源B,线程2锁住资源B等待资源A,两个线程都在等待自己需要的资源 而这些资源被另外的线程锁住,这些线程你等我,我等你,谁也不愿意让出资源,这样死锁就产生了。举一个形象的例子2个人(2个线程)要过一个独木桥(资源),两人走到中间停下来等另外一个人让路,不幸的是没有人愿意让路,于是两人就无限期的等下去了。
public class DeadLockTest implements Runnable {
    public boolean flag = true;
    static Object res1 = new Object();
    static Object res2 = new Object();
   
    public void run() {
        if(flag) {
            /**//* 锁定资源res1 */
            synchronized(res1) {
                System.out.println("Resource 1 is locked. Waiting for Resource 2.");
                try {
                    Thread.sleep(1000);
                }
                catch (InterruptedException e) {}
                /**//* 锁定资源res2 */
                synchronized(res2) {
                    System.out.println("Complete.");
                }
            }
        }
        else {
            /**//* 锁定资源res2 */
            synchronized(res2) {
                System.out.println("Resource 2 is locked. Waiting for Resource 1.");
                try {
                    Thread.sleep(1000);
                }
                catch (InterruptedException e) {}
                /**//* 锁定资源res1 */
                synchronized(res1) {
                    System.out.println("Complete.");
                }
            }
        }
    }
   
    public static void main(String[] args) {
        DeadLockTest r1 = new DeadLockTest();
        DeadLockTest r2 = new DeadLockTest();
        r2.flag = false;
        Thread t1 = new Thread(r1);
        Thread t2 = new Thread(r2);
        t1.start();
        t2.start();
    }
}

运行结果:
Resource 1 is locked.
Waiting for Resource 2.
Resource 2 is locked.
Waiting for Resource 1.
。。。(死锁)


以上死锁可以通过规定访问锁资源的顺序来解决。

追踪程序效率点
一般我们使用一些工具来找出效率的关键点,在没工具的情况下可以使用最土的打时间日志方法。
比如使用jprofiler观察CPU数据如下:




从这个数据,可以找到各个方法调用次数和消耗的时间,很显然这个例子的Calendar.getInstance消耗了 70.9%的时间。我们的j2ee应用也可以使用这样的工具去找出这些效率点。
  • 大小: 6 KB
分享到:
评论

相关推荐

    Java类加密程序

    &lt;br&gt;举例说明:例如,本加密工具安装在c:\hideasoft\java_protect,执行加密后的CLASS文件的命令行如下: java -agentlib:c:\hideasoft\java_protect\hidea &lt;您的CLASS类及参数&gt; 应用场合 独立的应用...

    Java类加密2.0版本,无限制

    举例说明:例如,本加密工具安装在c:\lanswonsoft\java_protect,执行加密后的CLASS文件的命令行如下: java -agentlib:c:\lanswonsoft\java_protect\lanswon &lt;您的CLASS类及参数&gt; 应用场合 独立的应用程序...

    Python核心编程第二版(ok)

     1.3.10 高效的快速原型开发工具   1.3.11 内存管理器   1.3.12 解释性和(字节)编译性   1.4 下载和安装Python   1.5 运行Python   1.5.1 命令行上的交互式解释器   1.5.2 从命令行启动脚本 ...

    Python核心编程第二版

     1.3.10 高效的快速原型开发工具   1.3.11 内存管理器   1.3.12 解释性和(字节)编译性   1.4 下载和安装Python   1.5 运行Python   1.5.1 命令行上的交互式解释器   1.5.2 从命令行启动脚本 ...

    精通正则表达式~~~

    举例:修整股票价格... 51 自动的编辑操作... 53 处理邮件的小工具... 53 用环视功能为数值添加逗号... 59 Text-to-HTML转换... 67 回到单词重复问题... 77 第3章:正则表达式的特性和流派概览.... 83 在...

    jquery插件使用方法大全

    第二行代码得到class 为container的div元素,第三行代码得到标签下面id为msg的div元素(不过最好别这样写,因为jQuery需要遍历所有的div元素,对于带id的元素,直接用$("#id"))。第四行代码得到context为上下文的table...

    C++大学教程,一本适合初学者的入门教材(part2)

    1.9 Java、Internet与万维网 1.10 其他高级语言 1.11 结构化编程 1.12 典型C++环境基础 1.13 C++与本书的一般说明 1.14 C++编程简介 1.15 简单程序:打印一行文本 1.16 简单程序:两个整数相加 1.17 内存的...

    C++大学教程,一本适合初学者的入门教材(part1)

    1.9 Java、Internet与万维网 1.10 其他高级语言 1.11 结构化编程 1.12 典型C++环境基础 1.13 C++与本书的一般说明 1.14 C++编程简介 1.15 简单程序:打印一行文本 1.16 简单程序:两个整数相加 1.17 内存的...

    Toad 使用快速入门

    帮助开发人员优化SQL,为他们提供各种优化模式下SQL执行计划,并且能够给出优化的建议,能够比较各种模式下实际的SQL运行结果,帮助开发人员真正高速地开发高效地代码。 Toad还可以外挂一些别的产品,比如PL/...

    XML轻松学习手册--XML肯定是未来的发展趋势,不论是网页设计师还是网络程序员,都应该及时学习和了解

    面向对象的思想方法已经非常流行了,在编程语言(例如java,js)中,都运用面向对象的编程思想。在XML中,就是要将网页也作为一个对象来操作和控制,我们可以建立自己的对象和模板。与对象进行交流,如何命令对象,...

    游戏之旅--我的编程感悟【有目录】

    这对理解硬件, 写出更好的代码, 还有软件调试都有莫大的帮助。 第4 章前Windows 时代 现在, Win d ows 一统江山, 它帮我们稳藏了硬件的许多东西。 这一章是对1 0 年前知识的一个回 顾,它们如今已经沉寂在历史中...

Global site tag (gtag.js) - Google Analytics