并发编程实践笔记——对象的共享之可见性

当读操作和写操作发生在不同的线程中,对共享变量的读和写操作会产生意料之外的结果。为了确保多个线程之间对内存写入操作的可见性,必须使用同步机制。

 

加锁的含义不仅仅局限于互斥行为,还包括内存可见性。为了确保所有线程都能看到共享变量的最新值,所有执行读操作或者写操作的线程都必须在同一个锁上进行。

 

造成内存可见性问题的情况有:

 

1.编译器重排序。

当在没有同步机制保护的情况下读取某个共享变量,编译器可能会对代码的执行顺序进行重排序,常见的情况有在while循环中判断一个共享的boolean变量,而在while循环中又没有更改该boolean变量的值,而是在其他线程中修改该值,并且此时jvm的启动模式为-server(server模式会做更多的编译优化),就可能会发生编译器重排序现象。

 

2.对于共享数据的多线程读写操作,没有使用同一个锁进行保护。

常见的现象是,虽然对一个共享对象的私有属性进行了get和set封装,但在get set方法中没有使用同一个锁进行同步保护,在使用set方法的时候,其他线程依然可以使用get方法对私有属性进行读取而不受互斥保护。

 

3.非原子的64位操作。

  在64JVM中,允许将一个64位的读操作或者写操作分解为两个32位操作,所以,如果在读取一个非volatile类型的long或者double变量时,如果对该变量的读操作和写操作在不同的线程中执行,那么很可能会读到某个值的高32位和另一个值的低32位。所以,在多线程程序中使用共享且可变的long或者double等类型的变量也是不安全的,除非用关键字volatile来声明他们,或者用锁保护起来。

 

Volatile变量

  当把变量声明为volatile类型后,编译器与运行时都会注意到这个变量是共享的,因此不会将该变量上的操作与其他内存操作一起重排序。volatile变量不会被缓存在寄存器或者对其他处理器不可见的地方。在访问volatile变量时不会执行加锁操作,因此也就不会使执行线程阻塞,因此volatile变量是一种比synchronized关键字更为轻量级的同步机制。

但在使用volatile变量时需要注意,因为其在访问时不会执行加锁操作,所以它只适合使用在一些特别简单的读写访问场合,比如只对该变量进行一次读或者写操作,如果需要对可见性进行复杂的判断(比如先判断后改写),那么就不应该使用这种同步策略。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值