Java并发之同步 —— volatile关键字及原子性、可见性、有序性

前言

在理解volatile前,先理解原子性、可见性、有序性

原子性:

操作的不可分割性。如++count 实际上是可以分割的三个独立操作,读取->修改->写入,其结果依赖之前的状态,所以并非原子性

可见性:

一个线程修改了对象状态后, 其他线程能够看到发生的状态变化

 "可见性是一种复杂的属性,因为可见性中的错误总是会违背我们的直觉。在单线程环境中,如果向某个变量先写入值,然后在没有其他写入操作的情况下读取这个变量,那么总能得到相同的值。这看起来很自然。然而,当读操作和写操作在不同的线程中执行时,情况却并非如此,这听起来或许有些难以接受。通常,我们无法确保执行读操作的线程能适时地看到其他线程写入的值,有时甚至是根本不可能的事情。为了确保多个线程之间对内存写入操作的可见性,必须使用同步机制。"  

java内存模型中通过Happens-Before规则来保证可见性。

有序性:

在多个线程执行指令操作时,JMM(Java内存模型)会通过指令重排序来优化操作。但在没有充分同步的程序中,如果调度器采用不恰当的方式来交替执行不同线程的操作,那么将导致不正确的结果。更糟的是,JMM还使得不同线程看到的操作执行顺序是不同的,从而导致徉缺乏同步的情况下,要推断操作的执行顺序将变得更加复杂。

public class PossibleReordering {
    static int x = 0, y = 0 ;
    static int a = 0, b = 0;
    public static void main(String[] args) throws InterruptedException {
        Thread one = new Thread(new Runnable() {
            @Override
            public void run() {
                a = 1;
                x = b;
            }
        });
        Thread other = new Thread(new Runnable() {
            @Override
            public void run () {
                b = 1;
                y = a;
            }
        });
        one.start ( ) ; other.start();
        one.join( ) ; other.join( ) ;
        System.out.println("("+x+","+y+")"); //无法正确预测x , y的值
        }
}

所以我们需要通过一些方式与规则来保证多线程程序执行的有序性。

 

Volatile理解

1.当把变量声明为volatile类型后,编译器与运行时都会注意到这个变量是共享的, 因此不会将该变量上的操作与其他内存操作一起重排序。

2.volatile变量不会被缓存在寄存器或者对其他处理器不可见的地方,因此在读取volatile类型的变量时总会返回最新写入的值。

3.volatile变量的写入操作必须在对该变量的读操作之前执行(JMM的Happens-Before规则)

实例

volatile 关键字为实例域的同步访问提供了一种免锁机制。如果声明一个域为 volatile , 那么编译器和虚拟机就知道该域是可能被另一个线程并发更新的。 例如, 假定一个对象有一个布尔标记 done , 它的值被一个线程设置却被另一个线程査询,如同我们讨论过的那样,我们可以使用volatile关键字:

private volatitle boolean done;
public boolean isDoneO { return done; }
public void setDoneO { done = true; }

 

局限性

volatile 变量不能提供原子性。例如方法,

public void flipDone() { done = !done; } // not atomic 

不能确保翻转域中的值。不能保证读取、 翻转和写入不被中断。

使用条件

当且仅当满足以下所有条件时,才应该使甩volatile变量: 

  • 对变量的写人操作不依赖变量的当前值,或者你能确保只有单个线程更新变量的值。
  • 该变量不会与其他状态变量一起纳人不变性条件中。
  • 在访问变量时不需要加锁。

小结 

加锁机制既可以确保可见性又可以确保原子性,而volatile变量只能保证可见性。

 

参考:Java并发编程实战

          Java核心技术 卷I 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值