不同于 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() {
}