不同于 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(); }
}
什么是区域锁 (Scoped Lock)
区域锁是指线程执行进入一个区域时,一个锁将自动被获取,当该线程执行离开这个区域时,这个锁将被自动释放。 C++ 区域锁的实现使用了 RAII 技术 , 实现如下。
清单 3. Scoped Lock Using C++
template <class LOCK>
class Guard {
public:
// Store a pointer to the lock and acquire the lock.
Guard (LOCK &lock)
:m_pLlock (&lock), m_bOwner (false) {
m_pLlock->acquire ();
m_bOwner = true;
}
// Release the lock when the guard goes out of scope,
// but only if <acquire> succeeded.
virtual ~Guard () {
if (m_bOwner) m_pLlock->release ();
}
private:
// Pointer to the lock we're managing.
LOCK *m_pLlock;
// Records if the lock is held by this object.
bool m_bOwner;
// ... maybe need disallow copying and assignment ...
};
Guard 是一个模板类,LOCK 类型指的是对操作系统提供的线程锁的抽象,比如,在 Windows 平台上,LOCK 可以是对 CRITICAL_SECTION 的封装。
那么对于 Java,怎么实现区域锁呢?不必担心,Java 对于区域锁模式在语言层面上已经做了封装,所以对于 Java 开发者来说,不必像 C++ 这样来开发自己的区域锁类,这就是我们所熟知的 synchronized 关键字。
清单 4. Scoped Lock Using Java
public int scopedLockSample() {
synchronized(this) {
try {
//do some work…
} catch( MyException1 e) {
//no need release lock explicitly
return -1;
} catch( MyException2 e) {
//no need release lock explicitly
return -2;
}
//other exceptions handling...
}
return 0;
}
class Message_Queue {
public:
enum { MAX_MESSAGES = 100/* ... */ };
// The constructor defines the maximum number
// of messages in the queue. This determines when the queue is 'full.'
Message_Queue(size_t max_messages = MAX_MESSAGES);
virtual ~Message_Queue();
// Put the <Message> at the tail of the queue.
// If the queue is full, block until the queue is not full.
/* synchronized */
void put (const Message &msg);
// Get the <Message> from the head of the queue
// and remove it. If the queue is empty, block until the queue is not empty.
/* synchronized */
Message get();
// True if the queue is empty, else false.
/* synchronized */
bool empty () const;
// True if the queue is full, else false.
/* synchronized */
bool full () const;
private:
// Put the <Message> at the tail of the queue, and
// get the <Message> at its head, respectively.
// Note that, the internal methods are not synchronized.
void put_i (const Message &msg);
Message get_i ();
// True if the queue is empty, else false.
bool empty_i () const;
// True if the queue is full, else false.
bool full_i () const;
private:
// Internal Queue representation omitted, could be a
// circular array or a linked list, etc.. ...
// Current number of <Message>s in the queue.
size_t message_count_;
// The maximum number <Message>s that can be
// in a queue before it's considered 'full.'
size_t max_messages_;
// Monitor lock that protects the queue's
// internal state from race conditions during concurrent access.
mutable Thread_Mutex monitor_lock_;
// Condition variable used in conjunction with <monitor_lock_> to make
// synchronized method threads wait until the queue is no longer empty.
Thread_Condition not_empty_;
// Condition variable used in conjunction with <monitor_lock_> to make
// synchronized method threads wait until the queue is no longer full.
Thread_Condition not_full_;
};
清单 7. Message_Queue.cpp
#include "Message_Queue.h"
Message_Queue::Message_Queue (size_t max_messages)
:not_full_(monitor_lock_),
not_empty_(monitor_lock_),
max_messages_(max_messages),
message_count_(0) {
}
bool Message_Queue::empty () const {
Guard<Thread_Mutex> guard (monitor_lock_);
return empty_i ();
}
bool Message_Queue::full () const {
Guard<Thread_Mutex> guard (monitor_lock_);
return full_i ();
}
void Message_Queue::put (const Message &msg) {
// Use the Scoped Locking idiom to acquire/release the < monitor_lock_> upon
// entry/exit to the synchronized method.
Guard<Thread_Mutex> guard (monitor_lock_);
// Wait while the queue is full.
while (full_i ()) {
// Release < monitor_lock_> and suspend the
// calling thread waiting for space in the queue.
// The <monitor_lock_> is reacquired automatically when <wait> returns.
not_full_.wait ();
}
// Enqueue the <Message> at the tail.
put_i (msg);
// Notify any thread waiting in <get> that the queue has at least one <Message>.
not_empty_.notify ();
} // Destructor of <guard> releases <monitor_lock_>.
Message Message_Queue::get () {
// Use the Scoped Locking idiom to acquire/release the <monitor_lock_> upon
// entry/exit to the synchronized method.
Guard<Thread_Mutex> guard (monitor_lock_);
// Wait while the queue is empty.
while (empty_i ()) {
// Release <monitor_lock_> and suspend the
// calling thread waiting for a new <Message> to
// be put into the queue. The <monitor_lock_> is
// reacquired automatically when <wait> returns.
not_empty_.wait ();
}
// Dequeue the first <Message> in the queue and update the <message_count_>.
Message m = get_i ();
// Notify any thread waiting in <put> that the
// queue has room for at least one <Message>.
not_full_.notify ();
return m;
} // Destructor of <guard> releases <monitor_lock_>.
bool Message_Queue::empty_i () const {
return message_count_ == 0;
}
bool Message_Queue::full_i () const {
return message_count_ == max_messages_;
}
Message_Queue::~Message_Queue() {
}