本文从典型的 Monitor Object 设计模式入手,从一个新的视角,来探讨 Java 语言的同步机制。
本文将从两个方面进行阐述:
1、使用 C++ 语言来描述 Monitor Object 设计模式。Java 对于这样一个典型的模式做了很好的语言层面的封装,因此对于 Java 的开发者来说,很多关于该模式本身的东西被屏蔽掉了。本文试图使用 Native C++ 语言,帮助读者从本质上对 Monitor object 设计模式有一个更全面的认识。
2、结合 C++ 版本的 Monitor Object 设计模式,引领读者对于 Java 同步机制有一个更深刻的认识,帮助读者正确有效地使用 Java 同步机制。
预备知识
在开始正式讨论之前,需要了解一些预备知识。
什么是 RAII
资源获取即初始化(RAII, Resource Acquisition Is Initialization)是指,在一个对象的构造函数中获得资源 , 并且在该对象的析构函数中释放它。这个资源可以是对象、内存、文件句柄或者其它类型。实现这种功能的类,我们就说它采用了资源获取即初始化(RAII)的方式。 RAII 是一种很典型的语言惯用法,被很多的 OO 语言所使用,下面是 C++ 的例子。
清单 1. RAII Using C++
class Raii {
public:
// Store a pointer to the resource and initialize the resource.
Raii(Resource &resource)
:m_pRes (&resource){
m_pRes->initialize ();
}
// Close the resource when the execution goes out of scope.
virtual ~Raii() {
m_pRes->close ();
}
private:
// Pointer to the resource we're managing.
Resource *m_pRes;
// ... maybe need disallow copying and assignment ...
};
使用 RAII 的好处是:由于析构函数由系统自动调用,这样可以帮助我们自动地隐式释放我们所获取的资源。事情上,我们熟知的很多 c++ 技术都用到了这一设计模式,比如:智能指针 (Smart Pointer),以及我们接下来要讨论的范围锁 (Scoped Lock) .
不同于 C++,Java 对象没有析构函数,Java System 提供了 GC 来管理内存资源。而对于像数据库连接,Sockets 这样类型的资源, Java 提供了 finalize() 来处理。但是,请注意,Java 的 finalizer 与 C++ 的析构函数是不同的,finalize() 函数由 GC 异步地在某个恰当的时候调用,我们不能等同地使用 finalize() 来实现 C++ 里的 RAII .通常的做法是使用 Java 提供的 finally 语句块。
清单 2. RAII Using Java
MyResource res = null;
try {
res = new MyResource();
// Use the resource
} finally {
//At exit point, close the resource.
if (res != null) { res.close(); }
}