论坛首页 Java企业应用论坛

关于synchronized的疑问

浏览 60685 次
该帖已经被评为精华帖
作者 正文
   发表时间:2004-04-14  
我也知道线程是一个很大的学问
但让我烦恼的是虽然知道所谓的线程定义是什么,但和实际联系起来之后总会觉得无法判断什么是线程,该如何使用线程。
0 请登录后投票
   发表时间:2004-04-14  
jaghuang 写道
我也知道线程是一个很大的学问
但让我烦恼的是虽然知道所谓的线程定义是什么,但和实际联系起来之后总会觉得无法判断什么是线程,该如何使用线程。


贴一下我以前看线程的时候的部分笔记: 
 
在java中,每个对象只有一个相应的monitor,一个mutex,而每一个monitor都可以有多个“doors”可以进入,即,同一个monitor中被守护的代码可以在不同的地方,因为同一个对象可以出现在不同的代码段,只要mutex锁定的对象是同一个,每个入口都用Synchronized关键字表明,当一个线程通过了Synchronized关键字,它就所住了该monitor所有的doors。因此是mutex定义了monitor而不是代码。

为了方便理解monitor的概念举个例子:
    飞机山只有一个洗手间,很多乘客都想进去,但一次只能进去一个人,其他人必须等待,此时有如下对应关系:

   飞机:object
     乘客:各个线程
   洗手间:monitor
    洗手间门上的锁:mutex

因为同步的花销很大,因此要尽量避免:
1,不需要同步原子操作:一个原子操作不会被另一个线程中断,所以原子操作不需要被同步;
2,避免同步,在语言上意味着“不变性”,一个具有不变性的对象的状态在其创建之后就不会改变,因此不变的对象不需要同步;通常频繁的访问一个对象,而不修改它,那么该对象就不需要同步,好的方法是使该对象为不可变的;
3,使用同步包装器,用装饰模式可以在同步与不同步之间选择。

另,java规范中并没有要求wait()方法要作为原子操作实现的,因此,判断是否wait()的条件用while比if要好,因为if虽然在某些java实现中起作用,但是其行为实际是不明确的,用while条件也称spin lock,用其代替if只是为了保险起见。(关于这一点while和if偶理解的不是太明白)
0 请登录后投票
   发表时间:2004-04-14  
哈哈,楼上的网友们越来越经典了,都是举例说明,PF,PF!
  楼主如果不太了解线程的概念,可以参看操作系统一书,上面有比较详细的解释的。
0 请登录后投票
   发表时间:2004-04-15  
mochow说得前半部分和我理解的差不多
让我感兴趣的主要是后半部分所说的如何避免使用到线程这样东西
但看完后还是晕晕的,什么原子啦........ 看不懂。
有种又兴奋又悲哀的感觉
0 请登录后投票
   发表时间:2004-04-15  
凤舞凰扬 写道
当一段代码会执行得非常快(比如就想你上面的赋值,时间几乎可以不计),其实根本可以不需要用同步描述的,当你的代码段比较长,并且相当重要,那么就会需要了。

这样理解就不对了,同步不是这样来理解的。要理解同步的本质,就要明白操作系统是如何执行程序的。对于进程和线程,操作系统设计者的目的是从概念上简化编程模型,使编程显得更自然,更符合思维习惯。操作系统设计者为使用进程和线程来编程提供了一个假设条件,即进程和线程各自的执行流是连贯的,没有任何断续执行的现象。但是实际上(以单CPU系统为例),从系统实现的底层看起来,这些进程和线程的执行流是支离破碎的,并且这些破碎的执行流片断被CPU以某种方式(即操作系统的调度程序)组合成一个串行的、混合在一起的执行流,以此推动操作系统不断运行。问题就在这里,同步问题的根源就在于看起来连贯的执行流实际上是破碎的。破碎的执行流会造成什么问题呢?比如有两个执行流A和B,A对现在需要对一个数据进行操作,但是这个操作被分割成了相连的两块执行流碎片,而另外一个执行流B本来需要在A完成这个数据操作之后才能取到这个数据然后进行它自己的计算,可是由于A对数据本应完整的操作被分割成了相连的两部分,然后CPU在A的碎片之间插入了B的取数这样一个执行流片断。这样一来,程序的行为就不符合我们原本所设想的那样,程序运行的结果就会出错。同步的本质就是让CPU不要把A的数据操作分割开,不让B有机会错误的横插一杠进来扰乱A,以保证正确的执行顺序,这样才能得到正确的我们想要的结果。不管你看起来执行得多么快的操作,都有可能被操作系统打断,从而形成碎片,导致无法预料的结果。所以,应该在需要精确时序的地方使用同步,而不是根据这个操作快不快来判断。所谓需要精确时序场合,其实就是数据的使用或操作的执行存在依赖性的地方,对于代码来说,就是完成某项操作时对参与的进程或线程执行顺序存在依赖性的代码块。
0 请登录后投票
   发表时间:2004-04-15  
youngS 写道


这样理解就不对了,同步不是这样来理解的。要理解同步的本质,就要明白操作系统是如何执行程序的。对于进程和线程,操作系统设计者的目的是从概念上简化编程模型,使编程显得更自然,更符合思维习惯。操作系统设计者为使用进程和线程来编程提供了一个假设条件,即进程和线程各自的执行流是连贯的,没有任何断续执行的现象。但是实际上(以单CPU系统为例),从系统实现的底层看起来,这些进程和线程的执行流是支离破碎的,并且这些破碎的执行流片断被CPU以某种方式(即操作系统的调度程序)组合成一个串行的、混合在一起的执行流,以此推动操作系统不断运行。问题就在这里,同步问题的根源就在于看起来连贯的执行流实际上是破碎的。破碎的执行流会造成什么问题呢?比如有两个执行流A和B,A对现在需要对一个数据进行操作,但是这个操作被分割成了相连的两块执行流碎片,而另外一个执行流B本来需要在A完成这个数据操作之后才能取到这个数据然后进行它自己的计算,可是由于A对数据本应完整的操作被分割成了相连的两部分,然后CPU在A的碎片之间插入了B的取数这样一个执行流片断。这样一来,程序的行为就不符合我们原本所设想的那样,程序运行的结果就会出错。同步的本质就是让CPU不要把A的数据操作分割开,不让B有机会错误的横插一杠进来扰乱A,以保证正确的执行顺序,这样才能得到正确的我们想要的结果。不管你看起来执行得多么快的操作,都有可能被操作系统打断,从而形成碎片,导致无法预料的结果。所以,应该在需要精确时序的地方使用同步,而不是根据这个操作快不快来判断。所谓需要精确时序场合,其实就是数据的使用或操作的执行存在依赖性的地方,对于代码来说,就是完成某项操作时对参与的进程或线程执行顺序存在依赖性的代码块。


说得比较清楚,但是不分段看得头晕,原子操作简单点理解就是那些不是被分割开的操作。比如基本类型里的int的赋值操作。

顺便罗嗦一下在基本类型里,除了long,double和boolean(这个得看具体的实现了)之外,其他的类型的赋值操作都是原子操作。因为long和double都是64位的,jvm对他们处理的时候是分成两部分处理的,高32位和低32位,如果多个线程访问这个赋值操作的时候没有同步的话,还是会出现问题。
0 请登录后投票
   发表时间:2004-04-15  
楼上指点的是,本来我只是想更加浅显地指出在什么条件下需要考虑多线程,在什么条件下可以忽略。呵呵,无奈,怎么表达,都感觉不对。
  楼上的帖子可以供楼主好好参考,呵呵,这可是从操作系统级的多线程概念吸收而来的哦~~~~~~~~~~~~
0 请登录后投票
   发表时间:2004-04-16  
建议楼主写些applets程序加深理解
0 请登录后投票
   发表时间:2004-04-16  
mochow 兄好久不见,您的大作无缘拜读,盼望早日在大陆出版。


引用
另,java规范中并没有要求wait()方法要作为原子操作实现的,因此,判断是否wait()的条件用while比if要好,因为if虽然在某些java实现中起作用,但是其行为实际是不明确的,用while条件也称spin lock,用其代替if只是为了保险起见。(关于这一点while和if偶理解的不是太明白)


关于同步和lock的思考,向来是java乃至所有系统中的重大问题。
同步并非lock. 也就是说,假若同一资源被多个线程竞争,仅仅用if是不够的,才需要spin lock. spin lock的本意就是在多个线程竞争时通过一个while进一步判断某些约束条件。

使用if的话,就要通过一个中间变量来传递这个条件,仍然可以达到完全lock,应该没有不保险一说。

下面的这个链接中是dev Central 上的一篇相当出色的文章的例子,恰好有使用while的spin lock和直接用boolean + if完成lock 的例子,特此奉上与诸公同阅。

http://devcentral.iticentral.com/articles/Java/thread_sync/code.html

(文章在此:http://devcentral.iticentral.com/articles/Java/thread_sync/default.php )
0 请登录后投票
   发表时间:2004-04-16  
曹晓钢 写道
mochow 兄好久不见,您的大作无缘拜读,盼望早日在大陆出版。


关于同步和lock的思考,向来是java乃至所有系统中的重大问题。
同步并非lock. 也就是说,假若同一资源被多个线程竞争,仅仅用if是不够的,才需要spin lock. spin lock的本意就是在多个线程竞争时通过一个while进一步判断某些约束条件。

使用if的话,就要通过一个中间变量来传递这个条件,仍然可以达到完全lock,应该没有不保险一说。

下面的这个链接中是dev Central 上的一篇相当出色的文章的例子,恰好有使用while的spin lock和直接用boolean + if完成lock 的例子,特此奉上与诸公同阅。

http://devcentral.iticentral.com/articles/Java/thread_sync/code.html

(文章在此:http://devcentral.iticentral.com/articles/Java/thread_sync/default.php )



此mochow非彼mochow,老兄,你认错人了。
偶只是个大陆的小菜鸟罢了

BTW:怎么还有别人也叫mochow的吗?
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics