线程中的的资源(二)

来源:互联网 发布:同志电影app软件 编辑:程序博客网 时间:2024/06/06 13:21

  在有关java中的讨论中,一个常不正确地知识是“原子操作不需要进行同步控制”。原子操作是不能被线程调度机制中断的操作;一旦操作开始,那么它一定可以在可能发生的“上下文切换”之前执行完毕。

  原子性可以应用于除long和double之外的所有基本类型之上的“简单操作”。对于读取和写入这些基本类型变量这样的操作,可以保证它们会被当作不可分的操作来操作内存。但是JVM可以将64位(long和double变量)的读取和写入当作两个分离的32位操作来执行,这就产生了在一个读取和写入操作中间发生上下文切换,从而导致不同的任务可以看到不正确结果的可能性。但是,当你定义Long和double变量时,如果使用volatile关键字,就会会获得原子性。

  volatile关键字还确保了应用中的可视性。如果你将一个域声明为volatile的,那么只要对这个域产生了写操作,那么所有的读操作都能看到这个修改。即便使用了本地缓存,情况也确实如此,volatite域会立即写入到主存中,而读取操作就发生在主存中。

  理解原子性和易变性是不同的概念这一点很重要。
  
  

  基本上,如果一个域可能会被多个任务同时访问,或者这些任务中至少有一个是写入任务那么你就应该把这个域的设置为volatile的。如果你将一个域定义为volatile,那么它就会告诉编译器不要执行任何一处读取和写入操作的优化,这些操作的目的是用线程中的局部变量维护对这个域的精确同步。

  与锁相比,Volatile 变量是一种非常简单但同时又非常脆弱的同步机制,它在某些情况下将提供优于锁的性能和伸缩性。如果严格遵循 volatile 的使用条件 —— 即变量真正独立于其他变量和自己以前的值 —— 在某些情况下可以使用 volatile 代替 synchronized 来简化代码。然而,使用 volatile 的代码往往比使用锁的代码更加容易出错。本文介绍的模式涵盖了可以使用 volatile 代替 synchronized 的最常见的一些用例。遵循这些模式(注意使用时不要超过各自的限制)可以帮助您安全地实现大多数用例,使用 volatile 变量获得更佳性能。

1.临界区-同步控制块;

    synchronized (lock) {            }

  在进入此段代码前,必须得到lock对象的锁。如果其他线程已经得到这个锁,那么就得等到锁被释放以后,才能进入临界区。通过使用同步控制块,而不是对整个方法进行同步控制,可以使多个任务访问对象的时间性能得到显著提高。当然对于Lock对象来说我们也可以显示地创建临界区和synchronized方法一样。

2.在其他对象上同步:
    

  synchronized块必须给定一个在其上进行同步的对象,并且最合理的方式是,使用其方法正在调用的
当前对象:synchronized(this)。这种方式中,如果获得了synchronized块上的锁,那么该对象其他的synchronized方法和临界区就不能被调用了。因此,如果在this上同步,临界区的效果就会直接缩小在同步的范围内。
  这时候问题就来了:有时必须在另一个对象上同步,但如果你要这么做,就必须确保所有相关的任务都是在同一个对象上同步的。

0 0
原创粉丝点击