线程与锁·read(读取)活动(由主存)为以后的load(载入)传送主存中的主要变量的拷贝到线程工作变量的拷贝。 ·load(载入)活动(由线程)从主存将通过一个read(读取)放入的传送的值,送到线程的工作变量的拷贝中。 ·store(存储)活动为以后的write(写入)活动将线程工作变量的拷贝的内容传送到主存。 ·write(写入)活动(由主存)将通过store活动得来的线程工作变量的拷贝内容放到主存中的主要变量拷贝。 ·lock(锁定)活动(由紧密地同步于主存的线程)使一个线程获得一个锁定的声明。 ·unlock(解锁)活动(由紧密地同步于主存的线程)使一个线程释放一个锁定的声明。 因此,线程与变量之间的交互从前至后地由use,assign,load,和store活动的顺序组成。主存为每次load和write活动执行一次read,而为每次store执行一次write。一个线程与锁之间的交互是从前至后由lock和unlock活动顺序所组成。线程的所有的可见行为包含了线程在变量和锁的所有活动。 执行顺序 执行顺序的规则强制某些事件发生的顺序。在活动中的关系有4个基本约束。 ·由任何线程执行的活动全部编排次序过;这样,如果任何一个线程执行2个活动,那么其中一个在另一个之前。 ·主存中任何一个变量执行的活动都被编排过次序过;这样,如果在主存中的一个变量执行2个活动,则其中一个领先。 ·主存中任何一个锁执行的活动都被编排过次序;这样,主存中的一把锁执行了2个活动,则其中一个领先。 ·不允许活动跟在自身后面。 最后一条似微不足道,但是这必须分别规定并且完全明确。没有它,就有可能计划好一些线程的一系列活动和满足以上除最后一条外,所有规则的活动中有领先关系的活动执行次序。 线程间关不直接交互;它们只是通过共享内存来通讯。线程的活动与主存中的活动的关系 被约束在三个方面: 一些线程,以及主存执行的每次“lock”或unlock活动都是连带的。 ·每次线程的load活动与主存中read活动都是唯一的一对,而load跟随在read后面 ·每次线程的store活动与主存中的write是唯一的一对,而write跟随在store后面 以下部分的大多数规则进一步地约束了某些线程发生的次序。规则必须声明一个活动在另一个活动的前面或者后面。注意这些关系是传递的:如果活动A必须在活动B前,并且B必须在C前面,则A必须在C前面。程序员必须记住这些规则是关于活动的顺序的唯一约束;如果没有规则或规则的组合来制约活动A必须领先于活动B,那么一个实现会自由地在运行A前运行B,或执行B时并发执行A。这种自由是高性能的关键。反过来讲,一个实现并不要求利用所有的它的自由。 在以下规则中,措词“B必须在A与C中干涉”意味着活动B必须后于A而先于C。 变量的规则 让T成为一个线程并且让V成为一个变量。T关于V而引发的活动的约束: ·通过V的T执行一个use或assign活动:只有当程序依照Java程序设计语言的运行模式而指定运行的T,才被允许。例如:一个V发生的事件如同一个+号操作数要求一样,一个简单的 use活动发生在V;而V发生的事件如同指定操作数的=号,请示assign发生。给定的线程所有的use和assign活动 必须通过在运行时被线程指定的顺序而执行。如果下面的规则禁止T引发一个use请求作为它的下一个活动,T必须首先引发一个load。 ·在V上的T引发一个store活动,在V的T的assign和一个后来的V的T的load之间干涉。(形式上:一个线程不允许丢失它最近的赋值21:48 00-12-18)。 ·V上的T引发的assign(赋值)活动必须在V的T引发的load或store与V的T的store中干涉。 (形式上:一个线程是不被允许无理由情况下从工作内存回写数据到主存中去的) ·当一个线程建立后,它必须在引发变量的use和store前引发一个变量的assign或load活动。(形式上:一个新的线程以一个空的工作内存为开始) ·当一个变量被建立时,每个线程必须在这个变量上引发use和store活动之前先引发assign或load活动。(形式上:只有在主存中新的变量被建立时,并且在任何线程的工作内存中没有被初始化) 如果上面和下面的所有的的规则都被服从了,那么load和store活动可以被任何变量上的任何一个线程在任何时候被声明。 主存中引发的read和write活动也有这样一些约束: ·在工作变量拷贝V之上的线程T所引发的每个load活动,必须使V在主存中的主要拷贝所引发的read活动相应领先,并且load活动必须将read活动传送来的数据放入工作内存拷贝。 ·在工作变量拷贝V之上的线程T所引发的每个store活动,必须使V在主存中的主要拷贝所引发的相应的write滞后,并且write活动必须将store活动传送来的数据放入主要内存拷贝中去。 ·在变量V上的线程T引发的活动A成为一个load或store,并让活动P成为主存中变量V的相应的read或write活动。同样的,使活动B成为变量V的线程T的一部分load活动,并且让活动Q成为主存变量V的相应的read或write活动。如果A领先于B,那么P必须领先于Q。(形式上:任何主要拷贝中给定的变量的活动,在主存中引发的线程的利益以一种线程所请求的严密的顺序所编排。) 注意,最后的一条规则只适用于相同变量的一个线程。然而,这确是一条对于volatile变量来讲是非常重要的。 对于double和long类型的情况是非原子性的。 如果一个double或long类型的变量没有定义为volatile,那么对待load,store,read以及write活动的用途,就如同对于两个32位的变量一样:无论什么情况下,规则要求以上活动中的一个,以及二个被引发,其中一个对于32位。这是一种将64位的double或long型变量被编码成两个32位的方式。而以volatile定义的变量的load,store,read和write活动是原子性的,不可分割的,即使变量类型是double或long。 这个问题只是因为一个double或long变量的read或write活动被实际主存储器作为两个32位的read和write活动,这样在时间上分开执行了,则其它活动可能会加入它们之中。因此,如果两个线程并发地赋值到一个同样的共享的double或long变量中去,那么这个变量的并发的use活动将获得一个不等于两者中任何一个实际要赋予的值,但是是两个值的一些非独立的实现的混合物。 上一篇:Java的网络知识 下一篇:你的第一个Java(for UNIX(Linux)) 更多相关文章
|
推荐文章
精彩文章
|