Linux中国 Linux中国门户站!
设为主页 设为主页
收藏本站 收藏本站
 
当前位置 :首页 ->Linux技术 ->系统管理 ->正文

线程与锁

来源:Linux-cn.com 作者:Webmaster 时间:2007-05-05 点击: [收藏] [投稿]
  例子:可能的交换

  考虑一个类,它具有类变量a和b并且方法hither和yon:


class Sample { 
int a = 1, b = 2; 
void hither() { 
a = b; 
} 
void yon() { 
b = a; 
} 
} 

  现在假如这样的两个线程被建立,并且一个被命名为hither而另一个被命名为yon。那么,什么是活动的请求集合,并且什么是其约束的顺序?

  让我们考虑线程highter。根据规则,这个线程必须引发一个b的use活动,并且被在a的assign(赋值)所跟随。这是执行一个调用方法hither的最小请求开销。

  现在,线程的变量b第一个活动不能是use。但是可以是assign或load。因为程序中没有调用这样的一个assign,所有一个对b的assign(赋值)不能发生,所有一个b的load活动被请求。线程的load活动轮流通过主存请求一个对于变量b的预先的read活动。

  线程可以随意地sotre(存储)在assign(赋值)后所的值。如果这作了,那么store活动轮流通过主存请求一个随其后的write活动。

  这些情况对称为yon的线程也是一样的,但是a与b的角色相互交换了。

  所有的活动可以以下图所描述:

  (见图1)

  这里的从A到B的一个箭头表明A必须领先于B。

  主存储器所生产的活动顺序是什么样的呢?这个唯一的约束就是不可能a的write活动领先与a的read活动并且b的write活动领先于b的read活动,因为这个在图表中的因果关系的箭头形成了一个循环,以至于一个活动必须领先于其自身,而这是不可以的。假定store和write活动随意地产生,有三种可能的顺序使主存储器能够合理地执行活动。设ha和hb为a和b对于hither线程的工作区拷贝,设ya和yb是yon线程的工作区拷贝,并设ma和mb是主存储器的主拷贝。初始化ma=1并且mb=2。那么会有三种可能性作为这些活动的顺序:


write aread a, read bwrite b (then ha=2, hb=2, ma=2, mb=2, ya=2, yb=2) 
read awrite a, write bread b (then ha=1, hb=1, ma=1, mb=1, ya=1, yb=1) 
read awrite a, read bwrite b (then ha=2, hb=2, ma=2, mb=1, ya=1, yb=1) 

  因此在主存中的最后结果可能就是:b被复制到a,a被复制到b,或者a与b的值被交换了;些外,变量的工作区拷贝有可能不会相同。这将导致不正确,当然,假定这些结果之一都比另一个有希望的话。这是一个程序的行为必须依赖于时间的地方。

  当然,一个实现当然可以选择不去引发store和write活动,或者只引发这一双中的一个,导致另外的一些可能的结果。

  现在让我们修改这个例子来使use的同步方法:


class SynchSample { 
int a = 1, b = 2; 
synchronized void hither() { 
a = b; 
} 
synchronized void yon() { 
b = a; 
} 
} 

  让我们再一次考虑线程hither。根据规则,这个线程必须引发一个lock活动(在类SynchSample类的实例上hither被调动时)在hither的方法实体被运行之前。这是在b的use之后,并且a的assign之后。最后,在执行hither方法的实体之后,SynchSample类的的实例unlock活动会被引发。这是调用执行hither方法需要的最小需求。

  在些之后,b的load被请求,并由主存储器轮流请求一个前置运行的read活动。因为load跟随lock活动,而相应的read也必须跟随lock活动。

  因为unlock活动跟随a的assign,而store活动是强制的,它通过主存储器轮流请求后置运行的write活动。Write活动必须领先于unlock活动。

  对于线程yon的情况是一样的,但是a与b的角色会被互换。

  所有的活动可以用以下图来刻画:

  lock和unlock活动提供了进一步通过主存强制约束活动的顺序;而一个线程的lock活动在其它线程的lock和unlock活动之间不可被引发。此外,unlock活动要求store和write活动引发。它可能有两种情况:


write aread a, read bwrite b (then ha=2, hb=2, ma=2, mb=2, ya=2, yb=2) 
read awrite a, write bread b (then ha=1, hb=1, ma=1, mb=1, ya=1, yb=1) 

  当结束状态依靠于时间,执行的结果可能会一致。

  例子:不遵守顺序的wirtes(写)

  这个例子是相似于以前的一些章节的,除了一个方法对两个变量赋值,并且另一个方法读两个变量。考虑一个类,它有类变量a和b并且有方法to和fro:


class Simple { 
int a = 1, b = 2; 
void to() { 
a = 3; 
b = 4; 
} 
void fro() { 
System.out.println("a= " + a + ", b=" + b); 
} 
} 

  现在假如这两个线程被建立,并且称为to 而另一个线程则称为fro。那么它们所请求的活动集体是什么呢?而它们的执行顺序又是怎样约束的呢?

  让我们考虑这个称为to的线程。这个线程必须引发一个被b的assign活动所跟随的a的assign。这是运行方法to最基本的需要。因为这里没有同步,实现是否将被赋予的值存入内存是随意的!因此称为fro的线程可能获得的a是1或是3,并且可能获得的b是2或是4。

  现在假设这个to被同步,而fro没有:


class SynchSimple { 
int a = 1, b = 2; 
synchronized void to() { 
a = 3; 
b = 4; 
} 
void fro() { 
System.out.println("a= " + a + ", b=" + b); 
} 
} 


 如果您对本文有任何疑问或者建议,请到讨论区发表您的意见: >> 论坛入口 <<



上一篇:Java的网络知识   下一篇:你的第一个Java(for UNIX(Linux))

文章评论】 【收藏本文】 【推荐好友】 【打印本文】 【我要投稿】 【论坛讨论
更多相关文章