JAVA日常学习----volatile

并发编程中的三个概念

  • 原子性:一个操作和多个操作,要么全部执行完,要不全部不执行。
  • 可见性:多个线程同时访问一个变量时,一个线程修改了变量值,其他线程能够立即看见。
  • 有序性:程序按照代码先后顺序执行。JVM在编译时会发生指令重排序。

想要程序正确的执行,必须保证程序的原子性、可见性和有序性。否则程序执行出错。

JAVA内存模型规定所有变量存储在主存中(类似与物理内存),每个线程有自己的工作内存(类似于高速缓存),线程只能操作自己的工作内存,不能对主存进行操作,每个线程不能访问其他线程的工作内存。

 JAVA中对三性的保护:

原子性:在JAVA中对基本数据类型变量的读取和赋值是原子操作。

x = 10;//1
y = x;//2
x++;//3
x = x+1;//4

以上只有1是原子操作,该局直接将10赋值给x,也就是线程将数值10写入到工作内存中。

语句2有两个操作,1.读取x的值,2.写入到工作内存。

3和4有三个操作,1.读取x值,2.对值加一,3.写入到工作内存。

另外,在32位平台下对64位数据的读取和赋值是两个操作。但最新的JVM已经保证了该操作为原子操作。

可见性:volatile关键字可以保证变量的可见性。被volatile修饰的变量修改后会立即写入到内存中,其他线程读取时需要去内存中读取。普通变量在修改后,写入内存中的时间是不确定的。

另外,sychronized和lock也可以保证变量的可见性。他们可以保证只有一个线程同时访问同步代码,并在释放锁之前将修改的变量值刷新到内存中。

有序性:JAVA允许编译器和处理器对指令进行重排序,重排序不会影响到单线程的执行,但是会影响到多线程的执行,这里存在一个happens-before原则,如果虚拟机不能通过该原则推出指令的次序,那么虚拟机可以随意对他们进行重排序。

Volatile关键字:

一个变量被volatile修饰,那么这个变量:

  • 是可见的,一个线程修改了该变量的值,其他线程是可见的。
  • 禁止进行指令重排序。

volatile无法保证操作的原子性:

public class test {
    public volatile int inc = 0;
    public void increase() {
        inc++;
    }
    public static void main(String[] args) throws InterruptedException {
        test t = new test();
        for(int i=0;i<10;i++){
            new Thread(){
                public void run() {
                    for(int j=0;j<1000;j++)
                        t.increase();
                };
            }.start();
        }
        Thread.sleep(2000);
        System.out.println(t.inc);
    }
}

上面的代码发现:每次执行玩完成后,输出的inc不为10000,而是小于10000的不同的值,产生这种情况的执行顺序如下:

  • 线程1取出inc的值,被阻塞。
  • 线程2取出inc的值,进行+1,被阻塞(没有把增加1后的inc值赋值给inc)。
  • 线程1被唤醒,inc+1,赋值,同步到主存,线程1结束。
  • 线程2唤醒,将inc的值赋值给inc,同步到主存。(此部不需要读取缓存中的inc值,尽管此时线程2中的inc缓存行已经无效)

volatile禁止指令重排序,可以在一定程度上保证程序的有序性:当程序执行到volatile变量时,在其前面的操作已经全部执行,并且更改更新到内存中,结果对后面的操作可见,在其后面的操作没有进行。

volatile实现机制:

在加入了volatile关键字时,会多出一个lock前缀指令,相对于一个内存屏障,它有三个功能:

  • 指令重排序不会把屏障之前的指令排到屏障之后,也不会把屏障之后的指令排到屏障之前。
  • 强制对缓存的修改立即写入到主存。
  • 如果是写操作,会导致其他cpu对应的缓存行无效。

 

 

 

 

 

 

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值