AutoCAD 3DMAX C语言 Pro/E UG JAVA编程 PHP编程 Maya动画 Matlab应用 Android
Photoshop Word Excel flash VB编程 VC编程 Coreldraw SolidWorks A Designer Unity3D
 首页 > JAVA编程

编写高效的线程安全类

51自学网 2015-09-02 http://www.wanshiok.com

 

同步方法的分解

正如在前面看到的那样,同步方法获取对象的一个锁。如果该方法由不同的线程频繁调用,则此方法将成为瓶颈,因为它会对并行性造成限制,从而会对效率造成限制。这样,作为一个一般的原则,应该尽可能地少用同步方法。尽管有这个原则,但有时一个方法可能需要完成需要锁定一个对象几项任务,同时还要完成相当耗时的其他任务。在这些情况下,可使用一个动态的“锁定-释放-锁定-释放”方法。例如,清单 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() {
        // 获取时间的系统调用
        // 重绘时钟指针
    }
}

清单 9 中的代码示例不靠任何其他代码来调用 repaint() 方法。这样,将一个时钟并入一个较大的用户界面就相当简单。

事件驱动处理

当应用程序需要对事件或条件(内部的和外部的)作出反映时,有两种方法或用来设计系统。在第一种方法(称为轮询)中,系统定期确定这一状态并据此作出反映。这种方法(虽然简单)也效率不高,因为您始终无法预知何时需要调用它。

第二种方法(称为事件驱动处理)效率较高,但实现起来也较为复杂。在事件驱动处理的情况下,需要一种发信机制来控制某一特定线程何时应该运行。在 Java 程序中,您可以使用 wait()、notify() 和 notifyAll() 方法向线程发送信号。这些方法允许线程在一个对象上阻塞,直到所需的条件得到满足为止,然后再次开始运行。这种设计减少了 CPU 占用,因为线程在阻塞时不消耗执行时间,并且可在 notify() 方法被调用时立即唤醒。与轮询相比,事件驱动方法可以提供更短的响应时间。

创建高效的线程安全类的步骤

编写线程安全类的最简单的方法是用 synchronized 声明每个方法。虽然这种方案可以消除数据损坏,但它同时也会消除您预期从多线程获得的任何收益。这样,您就需要分析并确保在 synchronized 块内部仅占用最少的执行时间。您必须格外关注访问缓慢资源 — 文件、目录、网络套接字和数据库 — 的方法,这些方法可能降低您的程序的效率。尽量将对这类资源的访问放在一个单独的线程中,最好在任何 synchronized 代码之外。

 
 
说明
:本教程来源互联网或网友上传或出版商,仅为学习研究或媒体推广,wanshiok.com不保证资料的完整性。
 

上一篇:Java 理论与实践: 关于异常的争论  下一篇:如何使用线程