volatile

原文链接:https://my.oschina.net/heweipo/blog/738707

1、使用 volatile 修饰的变量,在多线程下的读写过程

 

2、volatile 是轻量级的synchronized,它在多处理器开发中保证了共享变量的可见性。

3、volatile之所以轻量级是因为volatile修饰的变量不会加锁,也就不会影响并发导致的阻塞、竞争、上下文切换。

4、共享变量的可见性是指当一个线程修改了共享变量时,另外一个线程能够能读到这个修改的值。

5、Java编程语言允许线程访问共享变量,为了确保共享变量能被准确和一致地更新,线程应该确保通过排它锁单独获得这个变量。如果使用volatile修饰了这个变量,那么Java线程内存模型可以保证所有线程看到的这个变量的值是一致的。

6、如果一个变量同时在多个线程的工作内存中存在副本,那么这个变量就叫共享变量。其实只有局部变量不是共享变量,其他的比如成员变量无论共有还是私有,无论静态还是非静态都是共享变量。

 

7、使用volatile修饰变量时写操作的流程

1)将当前处理器缓存行的数据写回到系统内存(处理器先将系统的内存更新到本地缓存副本,然后修改副本的值,最后把副本更新到系统内存,CPU是不会直接修改系统内存的。)。

2)这个写回内存的操作会使其他CPU里缓存了该内存地址的数据无效(这应该就是一个观察者模式,一旦系统内存发生变化,就应该通知下面的副本前来更新)。

总结:从上面两步操作可以得出volatile的写操作会更新所有的缓存副本,但是读操作不会受任何的影响,那么多线程情况下对volatile的变量同时读写,会产生错误数据,volatile变量的更新必须是独立的操作,不受其他任何值的条件关联。

比如: i++ ,这个受到i旧值的影响,先读取i,然后 i+1,然后写会内存中,假设在 i+1 的过程中另一个线程已经把 i 值更新了,当前线程还是不会知道的。

比如:low<high , 因为要依赖high的值,所以

总之:volatile的缺陷就是读写操作的时候没有排它锁,导致并发可能存在问题,解决这个问题就是在使用 volatile 变量时,不要去读其他的值或当前值,对volatile变量的修改是独立的。

 

 

8、CAS(Compare and Swap) 比较并交换。 其实就是比较系统中的值是否等于期望的值,如果等于就说明可以修改,否则说明有其他程序在修改,那么继续循环操作,直到与预期值相等。

java.util.concurrent包中借助CAS实现了区别于synchronouse同步锁的一种乐观锁。其实也就是原子类的 compareAndSet 方法。

 

9、具体实例:(单例模式)

/**

* Singleton model (懒汉式单例)

* @author:Heweipo

* @version 1.00

*

*/

public class Singleton {

// 一个锁,任何不为空的对象

private static Object lock = new Object();

// 单例实例,使用了 volatile,做判断时 instance == null 读取的instance和系统内存保存一致

private volatile static Singleton instance;

 

private Singleton(){

// do nothing

}

 

public static Singleton getInstance(){

// 其实可以在方法最外层枷锁,但是那样的话势必会影响性能,因为为空的情况只有一次出现

if(instance == null){

// 加锁lock,在这之前是可能有多个方法还未初始化单例时进入的,所以后面还有判断一次

synchronized(lock){

// 如果引用为空,那么实例化单例,这里为什么还要判断呢?目的是防止多个方法同时进入

if(instance == null){

//单例首次实例化

instance = new Singleton();

}

}

}

return instance;

}

}

 

转载于:https://my.oschina.net/heweipo/blog/738707

展开阅读全文
博主设置当前文章不允许评论。

没有更多推荐了,返回首页