码迷,mamicode.com
首页 > 编程语言 > 详细

Java对管程的支持

时间:2015-07-29 19:56:21      阅读:179      评论:0      收藏:0      [点我收藏+]

标签:

管程的概念

管程 (英语: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程序设计语言中,每个对象都可以作为一个管程。需要互斥使用的方法必须明确标示关键字synchronized. 代码块也可以标示关键字synchronized.
不使用明确的条件变量, Java的这种管程在入口队列之外,使用单独的条件等待队列. 所有等待的线程进入这个队列,
所有的notify与notify all操作也施加于这个队列。这种方法已经被其它程序设计语言使用,如C#.

技术分享

Java中的同步方法与其他经典管程有本质差别:Java没有内嵌的条件变量。反之,Java提供了两个过程wait和notify ,分别与sleep和wakeup等价
不过,当它们在同步方法中使用时,它们不受竞争条件约束。理论上,方法wait可以被中断,它本身就是与中断有关的代码。Java需要显式表示异常处理。

Java对管程的支持

标签:

原文地址:http://my.oschina.net/hosee/blog/485285

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!