同步方法的分解
正如在前面看到的那样,同步方法获取对象的一个锁。如果该方法由不同的线程频繁调用,则此方法将成为瓶颈,因为它会对并行性造成限制,从而会对效率造成限制。这样,作为一个一般的原则,应该尽可能地少用同步方法。尽管有这个原则,但有时一个方法可能需要完成需要锁定一个对象几项任务,同时还要完成相当耗时的其他任务。在这些情况下,可使用一个动态的“锁定-释放-锁定-释放”方法。例如,清单 7 和清单 8 显示了可按这种方式变换的代码。
清单 7. 最初的低效率代码
public synchonized void doWork() {
unsafe1();
write_file();
unsafe2();
}
清单 8. 重写后效率较高的代码
public void doWork() {
synchonized(this) {
unsafe1();
}
write_file();
synchonized(this) {
unsafe2();
}
}
清单 7 和清单 8 假定第一个和第三个方法需要对象被锁定,而更耗时的 write_file() 方法不需要对象被锁定。如您所见,重写此方法以后,对此对象的锁在第一个方法完成以后被释放,然后在第三个方法需要时重新获得。这样,当 write_file() 方法执行时,等待此对象的锁的任何其他方法仍然可以运行。将同步方法分解为这种混合代码可以明显改善性能。但是,您需要注意不要在这种代码中引入逻辑错误。
嵌套类
内部类在 Java 程序中实现了一个令人关注的概念,它允许将整个类嵌套在另一个类中。嵌套类作为包含它的类的一个成员变量。如果定期被调用的的一个特定方法需要一个类,就可以构造一个嵌套类,此嵌套类的唯一任务就是定期调用所需的方法。这消除了对程序的其他部分的相依性,并使代码进一步模块化。清单 9,一个图形时钟的基础,使用了内部类。
清单 9. 图形时钟示例
public class Clock {
protected class Refresher extends Thread {
int refreshTime;
public Refresher(int x) {
super("Refresher");
refreshTime = x;
}
public void run() {
while(true) {
try {
sleep(refreshTime);
}
catch(Exception e) {}
repaint();
}
}
}
public Clock() {
Refresher r = new Refresher(1000);
r.start();
}
private void repaint() {
// 获取时间的系统调用
// 重绘时钟指针
}
}