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数据如下:

[img]http://dl.iteye.com/upload/attachment/0074/0150/269fca76-d195-36bb-8465-b527763680f5.png[/img]


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值