看之前可以先看下java内存模型(http://www.cnblogs.com/nexiyi/p/java_memory_model_and_thread.html),可以更好理解本文
一、volatile
关键字volatile可以说是Java提供的最轻量级的同步机制,但是他并不容易完全被正确、完整地理解,以至于许多人都不去使用他。
当一个变量定义为volatile之后,他将具有两种特性,第一是保证此变量对所有线程的可见性,这里的“可见性”是指当一条线程修改了这个变量的值,新值对于其他线程来说是可以立即得知的。而普通变量不能做到这一点,普通变量的值在线程间传递需要通过主内存来完成,例如,线程A修改了一个普通变量的值,然后向主内存进行回写,另一条线程B在线程A回写完成了之后再从主内存进行读取操作,新变量值才会对线程B可见。
当一个共享变量被volatile修饰时,它会保证修改的值会立即被更新到主存,当有其他线程需要读取时,它会去内存中读取新值。而普通的共享变量不能保证可见性,因为普通共享变量被修改之后,什么时候被写入主存是不确定的,当其他线程去读取时,此时内存中可能还是原来的旧值,因此无法保证可见性。
另外,通过synchronized和Lock也能够保证可见性,synchronized和Lock能保证同一时刻只有一个线程获取锁然后执行同步代码,并且在释放锁之前会将对变量的修改刷新到主存当中。因此可以保证可见性。
volatile变量对所有线程是立即可见的,对volatile变量 所有的写操作都能立刻反应到其他线程当中,换句话说,volatile变量在各个线程中是一致的。当并不能得出“基于volatile变量的运算在并发下是安全的“这个结论。volatile变量在各个线程的工作内存中不存在一致性问题,但是Java里面的运算并非原子操作,导致volatile变量的运算在并发下一样是不安全的。
由于volatile变量只能保证可见性,在不符合以下两条规则的运算场景中,我们仍然要通过加锁来保证原子性。
- 运算结果并不依赖变量的当前值,或者能够确保只有单一的线程修改变量的值。
- 变量不需要与其他的状态变量共同参与不变约束。
synchronized(obj){//将obj对象锁定
//此处的代码块就是同步代码块
}
public synchronized void fun(){
//同步代码块
}
不管synchronized修饰的是方法还是对象,它始终锁定的是对象的实例变量,或者类变量。当执行同步代码块时,就会先获取该对象的同步监视器的锁,直到线程执行完同步代码块之后才会释放对同步监视器的锁定。