[关闭]
@chenxuxiong 2016-05-27T06:51:19.000000Z 字数 1988 阅读 600

volatile与synchronized

JAVA基础


1.volatile关键字的两层语义

  一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰之后,那么就具备了两层语义:

  1. //x、y为非volatile变量
  2. //flag为volatile变量
  3. x = 2; //语句1
  4. y = 0; //语句2
  5. flag = true; //语句3
  6. x = 4; //语句4
  7. y = -1; //语句5

  由于flag变量为volatile变量,那么在进行指令重排序的过程的时候,不会将语句3放到语句1、语句2前面,也不会讲语句3放到语句4、语句5后面。但是要注意语句1和语句2的顺序、语句4和语句5的顺序是不作任何保证的。

  并且volatile关键字能保证,执行到语句3时,语句1和语句2必定是执行完毕了的,且语句1和语句2的执行结果对语句3、语句4、语句5是可见的。

 如何禁止指令重排序?

我们可以观察对比加入volatile和未加入volatile关键字是所生成的汇编代码的差别。
通过对比我们发现有volatile修饰的变量赋值后,多执行了一个“lock add $0x0”的操作,这个操作相当于一个内存屏障(指令重排序时不能把后面的指令重排序到内存屏障之前的位置)。只有一个cpu访问内存时,不需要内存屏障;但若有多个,则需要内存屏障了,达到“指令重排序无法越过内存屏障”

3.volatile应用场景

用volatile必须具备以下2个条件:
  1)对变量的写操作不依赖于当前值,或者能够确保只有单一的线程修改变量的值。
  2)该变量没有包含在具有其他变量的不变式中 
例如 boolean类型,单例模式的双重检验锁

参考:http://www.cnblogs.com/dolphin0520/p/3920373.html

2.synchronized

当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码。
synchronized能保证操作的原子性

1.可以锁住对象,synchronized(this),锁住对象,只针对同个对象
2.可以锁住类,syschronized(XXX.class),锁住类,针对所有对象
3.可以锁住方法,syschronized int increa().锁住方法之前,等同锁住类
4.要注意的是,锁住的时候,其他同步代码块的部分会被暂时阻塞,非同步代码块不会阻塞,可以被访问

 一、当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。

 二、但是,当一个线程访问object的一个synchronized(this)同步代码块时,另一个线程仍然可以访问该object中的非synchronized(this)同步代码块。

 三、尤其关键的是,当一个线程访问object的一个synchronized(this)同步代码块时,其他线程对object中所有其它synchronized(this)同步代码块的访问将被阻塞。

 四、第三个例子同样适用其它同步代码块。也就是说,当一个线程访问object的一个synchronized(this)同步代码块时,它就获得了这个object的对象锁。结果,其它线程对该object对象所有同步代码部分的访问都被暂时阻塞。

 五、以上规则对其它对象锁同样适用.

与ReetranLock的区别

参考:http://www.cnblogs.com/GnagWang/archive/2011/02/27/1966606.html

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注