广告
|
Java编程语言的优点之一是它在语言层面上对多线程的支持。这支持中心同步:协调活动和多个线程之间的数据访问。Java用于支持同步的机制是显示器的问题。本章描述了监控和显示了Java虚拟机如何使用它们。它描述了监控的一个方面,锁定和释放的数据,指令集的支持。
监控
Java的监控支持两种类型的线程同步:相互排斥和合作。互斥,即支持Java虚拟机通过对象锁,允许多个线程对共享数据的独立工作而不互相干扰。合作,支持在Java虚拟机通过等待并通知类的方法 Object
,使线程能够朝着一个共同的目标一起工作。
显示器就像一个建筑包含一个特殊的房间,只能被一个线程。房间通常包含一些数据。从一个线程进入这个房间的时候叶子,它独占地访问任何数据在房间里。进入监控建筑被称为“进入监控。“进入建筑内部的特殊房间被称为“收购监视器。”占据房间被称为“拥有监控”,离开房间叫做“释放监视器。“把整个建筑被称为“退出监控。”
除了与一些相关数据,监视与一个或多个相关联的代码,而这本书将被监测区域。监视区域作为一个不可分割的操作需要执行的代码对一个特定的监控。换句话说,一个线程必须能够执行监控区域从头到尾没有另一个线程同时执行一个监控区域相同的监控。监控执行这one-thread-at-a-time执行的监控区域。线程可以输入一个监视器的唯一方法就是通过到达的开始与监测相关的监控区域之一。一个线程可以前进的唯一方法和执行监控区域是通过收购监视器。
当一个线程到达监测区域的开始,它是放在一个条目相关联的监视器。条目集就像前面走廊的监控。如果没有等待其他线程的入口设置,目前没有其他线程拥有监控,获得监视和继续执行的线程监控区域。当线程执行完���监控区域,它退出(和版本)监视器。
如果一个线程到达的开始监控区域保护的监控已经由另一个线程持有,新来的线程必须等待在条目集。当前所有者退出监控,新来的线程必须与任何其他线程也在条目集。只有一个线程将会赢得这场竞争,获得监控。
上面列出的第一种同步、互斥,指的是由多个线程互斥的执行监控区域。在任何时候,只有一个线程可以执行一个特定监测监控区域。一般来说,互斥是很重要的,只有当多个线程共享数据或其他资源。如果两个线程不处理任何常见的数据或资源时,他们通常不会相互干扰,不必执行相互排斥。在Java虚拟机实现,没有时间片,然而,一个高优先级的线程是永远不会阻塞干扰任何低优先级线程,即使没有一个线程共享数据。较高优先级的线程将独占CPU的低优先级线程。低优先级的线程将永远不会得到任何CPU时间。在这种情况下,监视保护没有数据可用于编排这些线程,以确保所有线程CPU时间。然而,在大多数情况下,通过监视器监视保护数据区域代码。在这种情况下,数据可以只通过访问监控区域,监控执行互斥访问这些数据。
上面列出的其他类型的同步监控支持合作。而互斥有助于保持线程干扰彼此共享数据时,合作有利于线程朝着共同的目标一起工作。
合作是重要的,当一个线程需要一些数据在一个特定的国家和另一个线程负责将数据输入。例如,一个线程,一个“读线程”,可以从缓冲区读取数据,另一个线程,一个写线程,是灌装。读线程需要缓冲在“不空”状态才能阅读任何数据的缓冲区。如果读线程发现缓冲区为空,它必须等待。写线程负责用数据填充缓冲区。一旦写线程所做的一些写作,读线程可以做一些阅读。
监控使用的Java虚拟机的形式被称为“等待并通知”监控。(有时也称为一个“信号”,继续监控)。在这种监视器,一个线程,目前拥有监视器可以暂停本身内部监控通过执行等待命令。当一个线程执行等等,它释放监测和进入一组等。将保持悬浮在等待的线程设置一段时间之后,另一个线程执行一个通知在监控命令。当一个线程执行通知,继续自己的监控,直到它释放监控自己的协议,通过执行一个等待或完成监控区域。通知线程释放了监视器后,等待线程将复活,重拾那些监控。
的监测中使用Java虚拟机有时被称为一个信号,继续监视因为一个线程通知(信号)它保留所有权的监测和监控地区继续执行(继续)。在一些以后,通知线程释放监测和复活一个等待线程。大概,等待线程暂停本身,因为数据保护的监控不是在一个国家允许线程继续做有用的工作���同时,通知的线程可能通知命令执行之后,把受保护的数据监控到等待线程所期望的状态。但是因为通知线程继续,它可能改变后的状态通知,等待线程仍然不能做有用的工作。另外,第三个线程可能获取通知后的监控线程释放,但在等待线程获得它之前,第三个线程可能改变了受保护的数据的状态。因此,通知必须在等待线程通常被认为是仅仅作为一个暗示可能存在所需的状态。每次复活一个等待线程,它可能需要再次检查状态,以确定是否能前进,做有用的工作。如果发现数据仍然不理想的状态,线程可以执行另一个等待或放弃,退出监控。
作为一个例子,考虑再一次上面描述的场景,包括一个缓冲区,一个读线程和写线程。假定缓冲保护的监控。当一个读线程进入监控保护缓冲,它检查缓冲区是否为空。如果缓冲区不是空的,读线程从缓冲区中读取和删除一些数据。满意,它退出监控。另一方面,如果缓冲区为空,读线程执行一个等待命令。尽快执行等,读线程暂停并放置到监控的等待。在这个过程中,读线程释放监视器,它可用其他线程。在一些以后,写线程进入监控,写一些数据到缓冲区,执行一个通知,出口监视器。写线程执行通知时,读线程标记为最终的复活。写线程退出监视器后,读线程是复活的所有者监控。如果有任何机会,其他线程都有留下的出现和使用数据写线程,读线程必须显式地检查以确保缓冲并不是空的。如果没有机会,任何其他线程消耗数据,然后读线程可以假设数据的存在。读线程从缓冲区中读取一些数据并退出监视器。
图形化描述的监控使用的Java虚拟机如图为20:1。这图显示了监控三个矩形。在中间,一个大矩形包含一个线程,监视器的主人。在左边,一个小矩形包含条目组。在右边,另一个小矩形包含活动线程等待。显示为灰黑圈。挂起线程显示为浅灰色圆圈。
![图20—1。一个Java的班长。](https://i-blog.csdnimg.cn/blog_migrate/2ed3fe9084fbe5d1598ffdcbecd81001.gif)
图20—1还展示了几个编号的大门,线程必须“通过”与监视器。当一个线程到达的开始监控区域,通过最左边的门进入监视器,一号门,和发现自己房屋的矩形入口设置。如果没有线程目前拥有监控和入口设置,没有其他线程正在等待的线程立即通过隔壁,二号门,成为监控的所有者。作为监控所有者,线程继续执行监控区域。另一方面,如果有另一个线程目前声称监视器的所有权,新来的线程必须等待在入口设置,可能还有其他线程已经等在那里。新来的线程被阻塞,因此不执行任何进一步进入监控区域。
图20—1显示在输入集和三个线程暂停四线程暂停等。这些线程将继续他们在哪里,直到当前的所有者监控——活跃线程释放监控。活动线程可以发布监控在两个方面:它可以完成监控区域执行或者执行等待命令。如果它完成了监控区域,它退出监控通过门的底部中央矩形,五号门。如果它执行一个等待命令,它会释放出监视器穿过三号门,门等。
如果前主人没有执行通知发布之前监视器(和没有一个等待线程之前通知,等待复活),那么只有线程条目集将获得监控竞争。如果前主人并执行通知,那么条目设置线程将不得不与一个或多个线程的等待。如果一个线���从入口集赢得竞争,它经过二号门,成为监控的新主人。如果一个线程等待设置赢得了竞争,它退出等设置和获取监控通过四号门。注意门3和4是唯一的线程可以进入或退出方式等设置,一个线程只能执行一个等待命令,如果目前拥有监视器,它不能离开等设置不自动成为监控的所有者。
在Java虚拟机中,线程可以执行等待命令时指定一个超时。如果一个线程指定超时,没有其他线程执行超时过期前通知,等待线程实际上从虚拟机接收自动通知。超时过期后,等待线程将会复活,即使没有其他线程都有一个明确的通知执行。
Java虚拟机提供了两种通知命令:“通知”和“通知所有。“通知命令选择任意一个线程等待设置和标志的最终复活。通知所有的命令是目前所有线程在等待最终的复活。
在很大程度上,一个Java虚拟机实现的方式选择下一个线程等待或条目集是一个决策的个人实现设计师。例如,实现设计师可以决定如何选择:o的线程等待设置订单通知命令o恢复线程的等待设置给定一个通知所有命令o,以便向入口设置线程获得监控o线程之间如何选择悬浮在等待通知后与入口集合命令你可能认为它有意义实现条目集等集先进先出(FIFO)队列,这样的线程等待时间最长的将会是第一个选择收购监视器。或者,它可能有意义有十个FIFO队列,每个优先级线程可以在Java虚拟机。虚拟机可以选择的线程等待时间最长的最高优先级队列中包含任何等待线程。实现可能会采取这样的方法,但是你不能依赖于它。实现自由实现条目等集方法暗含(LIFO)队列,选择低优先级线程之前,高优先级的线程,或做任何其他的事情没有意义。简而言之,实现自由选择线程以任意方式,收益率也难以分析的令人惊讶的排序。
作为一个程序员,你不能依赖于任何特定的优先级选择算法或治疗,至少如果你想编写一个Java程序,是平台独立的。例如,因为你不知道什么顺序中线程设置将选择等待复活的通知命令,您应该使用通知(而不是通知所有)只有当你绝对肯定只有一个线程悬浮在等待。如果有机会超过一个线程将暂停等设置在任何时候,您应该使用通知。否则,在一些Java虚拟机实现一个特定的线程可能被困在等待很长一段时间。如果通知总是选择最近的到来等待和等待集合总是包含多个线程,一些线程一直等待��最长可能永远不会复活。
教父JoshuaBloch说线程