




已閱讀5頁(yè),還剩8頁(yè)未讀, 繼續(xù)免費(fèi)閱讀
版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
Java Monitor Pattern本文從典型的 Monitor Object 設(shè)計(jì)模式入手,從一個(gè)新的視角,來(lái)探討 Java 語(yǔ)言的同步機(jī)制.本文將從兩個(gè)方面進(jìn)行闡述:1、使用 C 語(yǔ)言來(lái)描述 Monitor Object 設(shè)計(jì)模式.Java 對(duì)于這樣一個(gè)典型的模式做了很好的語(yǔ)言層面的封裝,因此對(duì)于 Java 的開(kāi)發(fā)者來(lái)說(shuō),很多關(guān)于該模式本身的東西被屏蔽掉了.本文試圖使用 Native C 語(yǔ)言,幫助讀者從本質(zhì)上對(duì) Monitor object 設(shè)計(jì)模式有一個(gè)更全面的認(rèn)識(shí).2、結(jié)合 C 版本的 Monitor Object 設(shè)計(jì)模式,引領(lǐng)讀者對(duì)于 Java 同步機(jī)制有一個(gè)更深刻的認(rèn)識(shí),幫助讀者正確有效地使用 Java 同步機(jī)制.預(yù)備知識(shí)在開(kāi)始正式討論之前,需要了解一些預(yù)備知識(shí).什么是 RAII資源獲取即初始化(RAII, Resource Acquisition Is Initialization)是指,在一個(gè)對(duì)象的構(gòu)造函數(shù)中獲得資源 , 并且在該對(duì)象的析構(gòu)函數(shù)中釋放它.這個(gè)資源可以是對(duì)象、內(nèi)存、文件句柄或者其它類型.實(shí)現(xiàn)這種功能的類,我們就說(shuō)它采用了資源獲取即初始化(RAII)的方式. RAII 是一種很典型的語(yǔ)言慣用法,被很多的 OO 語(yǔ)言所使用,下面是 C 的例子.清單 1. RAII Using Cclass 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 were managing. Resource *m_pRes; / . maybe need disallow copying and assignment . ;使用 RAII 的好處是:析構(gòu)函數(shù)由系統(tǒng)自動(dòng)調(diào)用,這樣可以幫助我們自動(dòng)地隱式釋放我們所獲取的資源.事情上,我們熟知的很多C技術(shù)都用到了這一設(shè)計(jì)模式,比如:智能指針 (Smart Pointer),以及我們接下來(lái)要討論的范圍鎖 (Scoped Lock) .不同于 C ,Java 對(duì)象沒(méi)有析構(gòu)函數(shù),Java System 提供了 GC 來(lái)管理內(nèi)存資源.而對(duì)于像數(shù)據(jù)庫(kù)連接,Sockets 這樣類型的資源, Java 提供了 finalize() 來(lái)處理.但是,請(qǐng)注意,Java 的 finalizer 與 C 的析構(gòu)函數(shù)是不同的,finalize() 函數(shù)由 GC 異步地在某個(gè)恰當(dāng)?shù)臅r(shí)候調(diào)用,我們不能等同地使用 finalize() 來(lái)實(shí)現(xiàn) C 里的 RAII .通常的做法是使用 Java 提供的 finally 語(yǔ)句塊.清單 2. RAII Using JavaMyResource res = null;try res = new MyResource(); / Use the resource finally /At exit point, close the resource. if (res != null) res.close(); 什么是區(qū)域鎖 (Scoped Lock)區(qū)域鎖是指線程執(zhí)行進(jìn)入一個(gè)區(qū)域時(shí),一個(gè)鎖將自動(dòng)被獲取,當(dāng)該線程執(zhí)行離開(kāi)這個(gè)區(qū)域時(shí),這個(gè)鎖將被自動(dòng)釋放. C 區(qū)域鎖的實(shí)現(xiàn)使用了 RAII 技術(shù) , 實(shí)現(xiàn)如下.清單 3. Scoped Lock Using Ctemplate 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 succeeded. virtual Guard () if (m_bOwner) m_pLlock-release (); private: / Pointer to the lock were managing. LOCK *m_pLlock; / Records if the lock is held by this object. bool m_bOwner; / . maybe need disallow copying and assignment . ;Guard 是一個(gè)模板類,LOCK 類型指的是對(duì)操作系統(tǒng)提供的線程鎖的抽象,比如,在 Windows 平臺(tái)上,LOCK 可以是對(duì) CRITICAL_SECTION 的封裝.Java 對(duì)于區(qū)域鎖模式在語(yǔ)言層面上已經(jīng)做了封裝,所以對(duì)于 Java 開(kāi)發(fā)者來(lái)說(shuō),不必像 C 這樣來(lái)開(kāi)發(fā)自己的區(qū)域鎖類,這就是我們所熟知的 synchronized 關(guān)鍵字.清單 4. Scoped Lock Using Javapublic 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; synchronized 保證在進(jìn)入該區(qū)域后,獲得對(duì)象鎖,不管最終該函數(shù)從哪里退出,該對(duì)象鎖都會(huì)被正確釋放.什么是條件變量 (Condition Variables)條件變量通常被一個(gè)線程用于使自己等待,直到一個(gè)涉及共享數(shù)據(jù)的條件表達(dá)式到達(dá)特定的狀態(tài).當(dāng)另外的協(xié)作線程指示共享數(shù)據(jù)的狀態(tài)已發(fā)生變化,調(diào)度器就喚醒在該條件變量上掛起的線程.于是新喚醒的線程重新對(duì)它的條件表達(dá)式進(jìn)行求值,如果共享數(shù)據(jù)已到達(dá)合適狀態(tài),就恢復(fù)處理.以下是條件變量的 C 實(shí)現(xiàn).清單 5. Thread Condition Using Cclass Thread_Condition public: / Initialize the condition variable and associate it with the specified lock Thread_Condition (const Thread_Mutex &m) :m_obMutex(m) cond_init (&cond_, USYNC_THREAD, 0); / Destroy the condition variable. virtual Thread_Condition () cond_destroy (&cond_); / Wait for the to be notified / or until has elapsed. / if = 0 then wait indefinitely. void wait (Time_Value *timeout = 0) cond_timedwait(&cond_, &m_obMutex.m_lock,timeout = 0 ? 0 : timeout-msec (); / Notify one thread waiting on . void notify () cond_signal (&cond_); / Notify all threads waiting on . void notify_all () cond_broadcast (&cond_); private: / Solaris condition variable. cond_t cond_; / Reference to mutex lock. const Thread_Mutex &m_obMutex; ;Thread_Condition 的實(shí)現(xiàn)與操作系統(tǒng)提供的 API 密切相關(guān),以上的例子是基于 Solaris condition variable API 的面向?qū)ο蟮姆庋b.另外,這里的 Thread_Mutex 類型是對(duì)操作系統(tǒng)提供的線程鎖的面向?qū)ο蟮姆庋b (Thread_Mutex 類型就是 Guard 模板參數(shù) LOCK 所指向的類型 ) .而對(duì)于 Java,問(wèn)題就變得簡(jiǎn)單很多,你不需要去封裝自己的條件變量類,Java 的根類 Object 提供了 wait/notify/notifyAll 方法給開(kāi)發(fā)者,很容易使用,這個(gè)我們?cè)诤竺娴挠懻撝袝?huì)看到.Monitor Object 設(shè)計(jì)模式 C 描述我們將從以下幾個(gè)方面來(lái)討論 Monitor Object 模式.問(wèn)題描述我們?cè)陂_(kāi)發(fā)并發(fā)的應(yīng)用時(shí),經(jīng)常需要設(shè)計(jì)這樣的對(duì)象,該對(duì)象的方法會(huì)在多線程的環(huán)境下被調(diào)用,而這些方法的執(zhí)行都會(huì)改變?cè)搶?duì)象本身的狀態(tài).為了防止競(jìng)爭(zhēng)條件 (race condition) 的出現(xiàn),對(duì)于這類對(duì)象的設(shè)計(jì),需要考慮解決以下問(wèn)題: 在任一時(shí)間內(nèi),只有唯一的公共的成員方法,被唯一的線程所執(zhí)行. 對(duì)于對(duì)象的調(diào)用者來(lái)說(shuō),如果總是需要在調(diào)用方法之前進(jìn)行拿鎖,而在調(diào)用方法之后進(jìn)行放鎖,這將會(huì)使并發(fā)應(yīng)用編程變得更加困難.合理的設(shè)計(jì)是,該對(duì)象本身確保任何針對(duì)它的方法請(qǐng)求的同步被透明的進(jìn)行,而不需要調(diào)用者的介入. 如果一個(gè)對(duì)象的方法執(zhí)行過(guò)程中,某些條件不能滿足而阻塞,應(yīng)該允許其它的客戶端線程的方法調(diào)用可以訪問(wèn)該對(duì)象.我們使用 Monitor Object 設(shè)計(jì)模式來(lái)解決這類問(wèn)題:將被客戶線程并發(fā)訪問(wèn)的對(duì)象定義為一個(gè) monitor 對(duì)象.客戶線程僅僅通過(guò) monitor 對(duì)象的同步方法才能使用 monitor 對(duì)象定義的服務(wù).為了防止陷入競(jìng)爭(zhēng)條件,在任一時(shí)刻只能有一個(gè)同步方法被執(zhí)行.每一個(gè) monitor 對(duì)象包含一個(gè) monitor 鎖,該鎖被同步方法用于串行訪問(wèn)對(duì)象的行為和狀態(tài).此外,同步方法可以根據(jù)一個(gè)或多個(gè)與 monitor 對(duì)象相關(guān)的 monitor conditions 來(lái)決定在何種情況下掛起或恢復(fù)他們的執(zhí)行.結(jié)構(gòu)在 Monitor Object 模式中,主要有四種類型的參與者: 監(jiān)視者對(duì)象 (Monitor Object): 負(fù)責(zé)定義公共的接口方法,這些公共的接口方法會(huì)在多線程的環(huán)境下被調(diào)用執(zhí)行. 同步方法:這些方法是監(jiān)視者對(duì)象所定義.為了防止競(jìng)爭(zhēng)條件,無(wú)論是否同時(shí)有多個(gè)線程并發(fā)調(diào)用同步方法,還是監(jiān)視者對(duì)象含有多個(gè)同步方法,在任一時(shí)間內(nèi)只有監(jiān)視者對(duì)象的一個(gè)同步方法能夠被執(zhí)行. 監(jiān)視鎖 (Monitor Lock): 每一個(gè)監(jiān)視者對(duì)象都會(huì)擁有一把監(jiān)視鎖. 監(jiān)視條件 (Monitor Condition): 同步方法使用監(jiān)視鎖和監(jiān)視條件來(lái)決定方法是否需要阻塞或重新執(zhí)行.執(zhí)行序列圖在監(jiān)視者對(duì)象模式中,在參與者之間將發(fā)生如下的協(xié)作過(guò)程:1、 同步方法的調(diào)用和串行化.當(dāng)客戶線程調(diào)用監(jiān)視者對(duì)象的同步方法時(shí),必須獲取它的監(jiān)視鎖.只要該監(jiān)視者對(duì)象有其他同步方法正在被執(zhí)行,獲取操作便不會(huì)成功.在這種情況下,客戶線程將被阻塞直到它獲取監(jiān)視鎖.當(dāng)客戶線程成功獲取監(jiān)視鎖后,進(jìn)入臨界區(qū),執(zhí)行方法實(shí)現(xiàn)的服務(wù).一旦同步方法完成執(zhí)行,監(jiān)視鎖會(huì)被自動(dòng)釋放,目的是使其他客戶線程有機(jī)會(huì)調(diào)用執(zhí)行該監(jiān)視者對(duì)象的同步方法.2、 同步方法線程掛起.如果調(diào)用同步方法的客戶線程必須被阻塞或是有其他原因不能立刻進(jìn)行,它能夠在一個(gè)監(jiān)視條件上等待,這將導(dǎo)致該客戶線程暫時(shí)釋放監(jiān)視鎖,并被掛起在監(jiān)視條件上.3、監(jiān)視條件通知.一個(gè)客戶線程能夠通知一個(gè)監(jiān)視條件,目的是為了讓一個(gè)前期使自己掛起在一個(gè)監(jiān)視條件上的同步方法線程恢復(fù)運(yùn)行.4、同步方法線程恢復(fù).一旦一個(gè)早先被掛起在監(jiān)視條件上的同步方法線程獲取通知,它將繼續(xù)在最初的等待監(jiān)視條件的點(diǎn)上執(zhí)行.在被通知線程被允許恢復(fù)執(zhí)行同步方法之前,監(jiān)視鎖將自動(dòng)被獲取.圖 1 描述了監(jiān)視者對(duì)象的動(dòng)態(tài)特性.示例在本節(jié)中,我們將使用監(jiān)視者對(duì)象設(shè)計(jì)模式來(lái)解決一個(gè)實(shí)際的問(wèn)題.這是一個(gè)典型的生產(chǎn)者/消費(fèi)者模式問(wèn)題.假定我們有一個(gè)固定長(zhǎng)度的消息隊(duì)列,該隊(duì)列會(huì)被多個(gè)生產(chǎn)者/消費(fèi)者線程所操作,生產(chǎn)者線程負(fù)責(zé)將消息放入該隊(duì)列,而消費(fèi)者線程負(fù)責(zé)從該對(duì)列中取出消息.清單 6. Message_Queue.hclass Message_Queue public: enum MAX_MESSAGES = 100/* . */ ; / 消息隊(duì)列中最大消息個(gè)數(shù)。當(dāng)達(dá)到這個(gè)數(shù)量時(shí),消息隊(duì)列為滿狀態(tài)(full)。 Message_Queue(size_t max_messages = MAX_MESSAGES); virtual Message_Queue(); / 將消息放在隊(duì)列的末尾。如果隊(duì)列已滿。阻塞并的不等待 /* synchronized */ void put (const Message &msg); / 從隊(duì)列中獲得消息。如果隊(duì)列為空,阻塞直到非空 /* synchronized */ Message get(); / /檢查消息隊(duì)列是否為空 /* synchronized */ bool empty () const; / 檢查消息隊(duì)列是否已滿 /* synchronized */ bool full () const; private: / 注意:內(nèi)部方法是不同步的 void put_i (const Message &msg); Message get_i (); bool empty_i () const; bool full_i () const; private: /省略隊(duì)列的內(nèi)部結(jié)構(gòu)??梢允茄h(huán)隊(duì)列或鏈表 size_t message_count_; size_t max_messages_; /在并發(fā)訪問(wèn)期間,監(jiān)視鎖隊(duì)列內(nèi)部狀態(tài),防止競(jìng)爭(zhēng)條件 Mutable Thread_Mutex monitor_lock_; /條件變量和監(jiān)視鎖聯(lián)合使用使同步方法線程等待直到消息隊(duì)列不空 Thread_Condition not_empty_; /條件變量和監(jiān)視鎖聯(lián)合使用使同步方法線程等待直到消息隊(duì)列未滿 Thread_Condition not_full_;單 7. Message_Queue.cpp#include Message_Queue.hMessage_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 guard (monitor_lock_); return empty_i ();bool Message_Queue:full () const Guard guard (monitor_lock_); return full_i ();void Message_Queue:put (const Message &msg) / Use the Scoped Locking idiom to acquire/release the upon/ entry/exit to the synchronized method. Guard guard (monitor_lock_);/ 等待直到隊(duì)列滿 while (full_i () /釋放監(jiān)視鎖,掛起調(diào)用線程,等待隊(duì)列中有多余空間 / 當(dāng)?shù)却祷貢r(shí),自動(dòng)獲得監(jiān)視鎖 not_full_.wait (); / 在消息隊(duì)列尾部加入消息 put_i (msg); / 通知在get時(shí)等待的線程消息隊(duì)列中有消息到達(dá) not_empty_.notify (); / 析構(gòu)guard釋放監(jiān)視鎖。Message Message_Queue:get () / Use the Scoped Locking idiom to acquire/release the upon / entry/exit to the synchronized method. Guard guard (monitor_lock_); /消息隊(duì)列為空時(shí)等待 while (empty_i () / 釋放監(jiān)視鎖,掛起調(diào)用線程等待新的消息到來(lái),wait返回時(shí)重新獲得監(jiān)視鎖。 not_empty_.wait (); / 獲取消息隊(duì)列中第一次消息,更新消息個(gè)數(shù) Message m = get_i (); / 通知在PUT中等待的線程,消息隊(duì)列中有空間可用(消息隊(duì)列未滿) not_full_.notify (); return m; / / 析構(gòu)guard釋放監(jiān)視鎖。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() Monitor Object Java 實(shí)踐認(rèn)識(shí) Java Monitor ObjectJava Monitor 從兩個(gè)方面來(lái)支持線程之間的同步,即:互斥執(zhí)行與協(xié)作. Java 使用對(duì)象鎖 (使用 synchronized 獲得對(duì)象鎖)保證工作在共享的數(shù)據(jù)集上的線程互斥執(zhí)行 , 使用 notify/notifyAll/wait 方法來(lái)協(xié)同不同線程之間的工作.這些方法在 Object 類上被定義,會(huì)被所有的 Java 對(duì)象自動(dòng)繼承.實(shí)質(zhì)上,Java 的 Object 類本身就是監(jiān)視者對(duì)象,Java 語(yǔ)言對(duì)于這樣一個(gè)典型并發(fā)設(shè)計(jì)模式做了內(nèi)建的支持.不過(guò),在 Java 里,我們已經(jīng)看不到了我們?cè)?C 一節(jié)所討論的區(qū)域鎖與條件變量的概念.下圖很好地描述了 Java Monitor 的工作機(jī)理.圖 2. Java Monitor線程如果獲得監(jiān)視鎖成功,將成為該監(jiān)視者對(duì)象的擁有者.在任一時(shí)刻內(nèi),監(jiān)視者對(duì)象只屬于一個(gè)活動(dòng)線程 (Owner) .擁有者線程可以調(diào)用 wait 方法自動(dòng)釋放監(jiān)視鎖,進(jìn)入等待狀態(tài).示例在本節(jié),我們將用 Java Monitor 來(lái)重新解決用 C 實(shí)現(xiàn)的生產(chǎn)者 / 消費(fèi)者模式問(wèn)題.清單 8. Message Classpublic class Message private static int OBJ_COUNT = 0; public int obj_index_; Message() synchronized(Message.class) OBJ_COUNT ; obj_index_ = OBJ_COUNT; Override public String toString() return message obj_index_ ; 清單 9. MessageQueue Classpublic class MessageQueue private int message_count_; private int max_messages_; private Message buffer_; private int in_ = 0, out_ = 0; public MessageQueue(int max_messages) max_messages_ = max_messages; message_count_ = 0; buffer_ = new Messagemax_messages_; synchronized boolean full () return full_i (); synchronized void put (Message msg) while (full_i () try System.out.println(thread+Thread.currentThread().getId()+ release monitor lock, wait for space in the queue); wait(); catch (InterruptedException e) /do something. finally /do something. /end while. put_i(msg); notifyAll(); synchronized Message get() while (empty_i () try System.out.println(thread+Thread.currentThread().getId() + release monitor lock, wait for message in the queue); wait(); catch (InterruptedException e) /do something. finally /do something. /end while. Message m = get_i (); notifyAll(); return m; private boolean empty_i () return message_count_ = 0; private boolean full_i () return message_count_ = max_messages_; private void put_i (Message msg) System.out.println(thread +Thread.currentThread().getId() + put message to the queue)
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 銀行風(fēng)險(xiǎn)防控體系評(píng)估與優(yōu)化研究
- 華為項(xiàng)目范圍管理辦法
- 村級(jí)經(jīng)濟(jì)規(guī)劃管理辦法
- 江蘇物業(yè)安全管理辦法
- 新工科實(shí)踐育人數(shù)字資源體系構(gòu)建
- 國(guó)際跨學(xué)科教育質(zhì)量評(píng)估體系比較研究
- 景區(qū)店鋪運(yùn)營(yíng)管理辦法
- 江西政務(wù)服務(wù)管理辦法
- 安全生產(chǎn)事故隱患泛指
- 擴(kuò)建工程的安全設(shè)施必須與主體工程
- 小規(guī)模稅務(wù)視頻教學(xué)課件
- 業(yè)務(wù)外包費(fèi)用管理制度
- 月子中心各部管理制度
- 痛風(fēng)的康復(fù)護(hù)理課件
- 公司自供自產(chǎn)品管理制度
- 2025-2030年中國(guó)多西他賽注射液行業(yè)市場(chǎng)深度分析及發(fā)展趨勢(shì)與投資研究報(bào)告
- 五育并舉與心理健康教育的融合
- 介入室耗材管理課件
- 三級(jí)直播銷售員(高級(jí))職業(yè)技能鑒定考試復(fù)習(xí)題及答案
- 炎癥后色素沉著防治專家共識(shí)(2024版)解讀
- T/SHPTA 093-2024漆面保護(hù)用聚氨酯薄膜
評(píng)論
0/150
提交評(píng)論