java volatile变量

valatile用来修饰共享变量,是一种弱的同步机制,用来确保将变量的更新操作通知到其他线程。

volatile实现原理

首先看一段代码:

public class SynchronizedExample {
    //一个控制变量,作为print方法的结束控制
    private  boolean asleep = false;

    public void print() {
        while (!asleep) {
            System.out.println("asleep == true");
            Thread.yield();
        }
    }

    public void set(){
        asleep = true;

}

    public static void main(String[] args) {
        SynchronizedExample obj = new SynchronizedExample();
        //线程调用了实例对象的print方法
        new Thread(new Runnable(){ public void run(){obj.print();}}).start();
        //线程将实例对象的控制开关关闭
        new Thread(new Runnable(){ public void run(){obj.set();}}).start();

    }
}

当第二个线程调用set方法后,线程一中的方法按理应该马上结束,但是在并发编程实战上强调这不是一个线程安全的对象,线程二调用set后线程一并不能立即看到修改后的asleep值。
现在问题来了:线程之间是共享成员变量的,为何线程二更改后线程一不能立刻看到修改?我在自己电脑上进行测试,多次运行并没有产生线程不安全的问题。于是我阅读了现代操作系统多处理机的章节,并且在网上找到了一篇很好的博文:聊聊并发(一)——深入分析Volatile的实现原理
问题在于在多处理机系统中,为了减少总线的压力提高每个CPU的性能,每个CPU都有一个高速缓存(即catche)。当引用一个字时,会将其从内存抽取到catche中。在单处理器系统中,存在的问题是catche和内存的不一致性,但是在多处理器中,多个线程在不同的CPU运行时,成员变量会存在于多个catche中。不一致性就存在于内存和多个catche之间。在硬件设计中已经给出了不一致性的一些解决方案,当某个CPU试图将修改后的字写回到内存当中时,总线硬件将会检测到写并且在总线上发送信号通知其他catche进行修改从而保证一致性。但是问题在于CPU修改catche之后何时将其写回到内存中。如果修改后立刻写回到内存当中,那么不会产生一致性问题。但是硬件设计当中通常是当这个字需要调出catche时才写回到内存中。
所以volatile的作用就是强制要求当catche中的成员变量发生更改时,立即写回到内存中。

和synchronized的区别

  • volatile不需要加锁,因此也不会发生阻塞,因此效率要高一点。
  • volatile只能保证可见性不能保证原子性。
    比如 idNum = count++;(count是volatile修饰的)这个操作依然是线程不安全的。因为当用加锁机制时,读取和自增的操作是一个原子操作,在自增完成前,其他线程不允许读取count的值,但是使用volatile时,一个线程刚刚完成自增的操作同时有多个其他的线程正在读取阶段,虽然这些线程能看到最后更改后的值,但是这些线程读取到的count值都是相同的。即volatile允许同时读但是加锁不允许同时读

总结

在并发编程实战中给出了volatile的适用范围:

  • 对变量的写入操作不依赖于变量的当前值(id = count++违反了这个原则),除非可以确保只有单个线程更新变量的值(例如用作某个操作完成,发生中断,或者状态的标志)。
  • 该变量不会和其他状态变量一起纳入不变性条件(原子性)
  • 在访问变量时不需要加锁(允许同时读)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值