歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Java對管程的支持

管程的概念

管程 (英語:Moniters,也稱為監視器) 是一種程序結構,結構內的多個子程序(對象或模塊)形成的多個工作線程互斥訪問共享資源。
這些共享資源一般是硬件設備或一群變量。管程實現了在一個時間點,最多只有一個線程在執行管程的某個子程序。
與那些通過修改數據結構實現互斥訪問的並發程序設計相比,管程實現很大程度上簡化了程序設計。
管程提供了一種機制,線程可以臨時放棄互斥訪問,等待某些條件得到滿足後,重新獲得執行權恢復它的互斥訪問。

一個管程包含:

  1. 多個彼此可以交互並共用資源的線程
  2. 多個與資源使用有關的變量
  3. 一個互斥鎖
  4. 一個用來避免競態條件的不變量

一個管程的程序在運行一個線程前會先取得互斥鎖,直到完成線程或是線程等待某個條件被滿足才會放棄互斥鎖。
若每個執行中的線程在放棄互斥鎖之前都能保證不變量成立,則所有線程皆不會導致競態條件成立。
當一個線程執行管程中的一個子程序時,稱為占用(occupy)該管程. 管程的實現確保了在一個時間點,最多只有一個線程占用了該管程。這是管程的互斥鎖訪問性質。
當線程要調用一個定義在管程中的子程序時,必須等到已經沒有其它線程在執行管程中的某個子程序。
在管程的簡單實現中,編譯器為每個管程對象自動加入一把私有的互斥鎖。該互斥鎖初始狀態為解鎖,
在管程的每個公共子程序的入口給該互斥鎖加鎖,在管程的每個公共子程序的出口給該互斥鎖解鎖。

條件變量(Condition Variable)

管程提供了一種實現互斥的簡便途徑,但這還不夠。我們還需要一種辦法使得線程在無法繼續運行時被阻塞。
在生產者-消費者問題中,很容易將針對緩沖區滿和緩沖區空的測試放到管程過程中,但是生產者在發現緩沖區滿的時候如何阻塞呢?
解決的方法是引入條件變量(condition variables)以及相關的兩個操作:wait和signal。
當一個管程過程發現它無法繼續運行時(例如,生產者發現緩沖區滿),它會在某個條件變量上(如full)執行wait操作。
該操作導致調用進程自身阻塞,並且還將另一個以前等在管程之外的進程調入管程。
另一個線程,比如消費者,可以喚醒正在睡眠的伙伴進程,這可以通過對其伙伴正在等待的一個條件變量執行signal完成。
為了避免管程中同時有兩個活躍進程,如果在一個條件變量上有若干進程正在等待,則在對該條件變量執行signal操作後,
系統調度程序只能在其中選擇一個使其恢復運行。

線程可能需要等待某個條件P為真,才能繼續執行。在一個忙等待(busy waiting)循環中
   while not( P ) do skip
將會導致所有其它進程都無法進入臨界區使得該條件P為真,該管程發生死鎖.
解決辦法是條件變量(condition variables). 概念上,一個條件變量就是一個線程隊列(queue), 其中的線程正等待某個條件變為真。
每個條件變量c關聯著一個斷言P_c. 當一個線程等待一個條件變量,該線程不算作占用了該管程,因而其它線程可以進入該管程執行,
改變管程的狀態,通知條件變量c其關聯的斷言P_c在當前狀態下為真.

因此對條件變量存在兩種主要操作:
wait c 被一個線程調用,以等待斷言P_c被滿足後該線程可恢復執行. 線程掛在該條件變量上等待時,不被認為是占用了管程.
signal c (有時寫作notify c)被一個線程調用,以指出斷言P_c現在為真.
當一個通知(signal)發給了一個有線程處於等待中的條件變量,則有至少兩個線程將要占用該管程: 發出通知的線程與等待該通知的某個線程. 
只能有一個線程占用該管程,因此必須做出選擇。兩種理論體系導致了兩種不同的條件變量的實現:
阻塞式條件變量(Blocking condition variables),把優先級給了被通知的線程.
非阻塞式條件變量(Nonblocking condition variables),把優先級給了發出通知的線程.

Java編程思想(第4版) 中文清晰PDF完整版 http://www.linuxidc.com/Linux/2014-08/105403.htm

編寫高質量代碼 改善Java程序的151個建議 PDF高清完整版 http://www.linuxidc.com/Linux/2014-06/103388.htm

Java 8簡明教程 http://www.linuxidc.com/Linux/2014-03/98754.htm

Java對象初始化順序的簡單驗證 http://www.linuxidc.com/Linux/2014-02/96220.htm

Java對象值傳遞和對象傳遞的總結 http://www.linuxidc.com/Linux/2012-12/76692.htm

隱式條件變量管程

Java程序設計語言中,每個對象都可以作為一個管程。需要互斥使用的方法必須明確標示關鍵字synchronized. 代碼塊也可以標示關鍵字synchronized.
不使用明確的條件變量, Java的這種管程在入口隊列之外,使用單獨的條件等待隊列. 所有等待的線程進入這個隊列,
所有的notify與notify all操作也施加於這個隊列。這種方法已經被其它程序設計語言使用,如C#.

Java中的同步方法與其他經典管程有本質差別:Java沒有內嵌的條件變量。反之,Java提供了兩個過程wait和notify ,分別與sleep和wakeup等價,
不過,當它們在同步方法中使用時,它們不受競爭條件約束。理論上,方法wait可以被中斷,它本身就是與中斷有關的代碼。Java需要顯式表示異常處理。在下文中,只要認為go_to_sleep就是去睡眠即可。

更多詳情見請繼續閱讀下一頁的精彩內容: http://www.linuxidc.com/Linux/2014-09/106539p2.htm

Copyright © Linux教程網 All Rights Reserved