谈谈你对Volatile的理解?

Volatile是Java虚拟机提供的轻量级的同步机制

Volatile三大特性:

1.保证可见性

//保证内存可见性
public class VolatileDemo {
    private volatile static int num=0;
    public static void main(String[] args) throws InterruptedException {
        new Thread(()->{
            while(num==0){
            }
        }).start();

        TimeUnit.SECONDS.sleep(1);
        num=1;
        System.out.println(num);
    }
}

2.不保证原子性

public class VDemo2 {

    private volatile static int num=0;
    public static void add(){
        num++;
    }

    public static void main(String[] args) {
        for(int i=0;i<=20;i++){
            new Thread(()->{
                for(int j=0;j<10000;j++) {
                    add();
                }
            }).start();
        }
        while(Thread.activeCount()>2){
             Thread.yield();
        }

        System.out.println(num);
    }
}

使用Atomic类来解决原子性不一致问题

import java.util.concurrent.atomic.AtomicInteger;

public class VDemo2 {

    private volatile static AtomicInteger num=new AtomicInteger();
    public static void add(){
        num.getAndIncrement();
    }

    public static void main(String[] args) {
        for(int i=0;i<=20;i++){
            new Thread(()->{
                for(int j=0;j<10000;j++) {
                    add();
                }
            }).start();
        }
        while(Thread.activeCount()>2){
             Thread.yield();
        }

        System.out.println(num);
    }

}

使用 synchronized来解决原子性不一致问题

public class VDemo2 {

    private volatile static int num=0;
    public synchronized static void add(){
        num++;
    }

    public static void main(String[] args) {
        for(int i=0;i<=20;i++){
            new Thread(()->{
                for(int j=0;j<10000;j++) {
                    add();
                }
            }).start();
        }
        while(Thread.activeCount()>2){
             Thread.yield();
        }

        System.out.println(num);
    }


}

3.禁止指令重排

普通类->
普通写->
内存屏障:禁止上下文交换->
Volatile写->
内存屏障:禁止上下文交换

内存屏障:

内存屏障(memory barrier) 是一个CPU指令。基本上,它是这样一条指令: a) 确保一些特定操作执行的顺序; b)
影响一些数据的可见性(可能是某些指令执行后的结果)。编译器和CPU可以在保证输出结果一样的情况下对指令重排序,使性能得到优化。插入一个内存屏障,
相当于告诉CPU和编译器先于这个命令的必须先执行,后于这个命令的必须后执行
。内存屏障另一个作用是强制更新一次不同CPU的缓存。例如,一个写屏障会
把这个屏障前写入的数据刷新到缓存,这样任何试图读取该数据的线程将得到最新值
,而不用考虑到底是被哪个cpu核心或者哪颗CPU执行的。

内存屏障有三种类型和一种伪类型:

a、lfence:即读屏障(Load
Barrier),在读指令前插入读屏障,可以让高速缓存中的数据失效,重新从主内存加载数据,以保证读取的是最新的数据。
b、sfence:即写屏障(Store
Barrier),在写指令之后插入写屏障,能让写入缓存的最新数据写回到主内存,以保证写入的数据立刻对其他线程可见。
c、mfence,即全能屏障,具备ifence和sfence的能力。
d、Lock前缀:Lock不是一种内存屏障,但是它能完成类似全能型内存屏障的功能。

内存屏障和volatile什么关系?

上面的虚拟机指令里面有提到,如果你的字段是volatile,Java内存模型将在写操作后插入一个写屏障
指令,在读操作前插入一个读屏障指令。这意味着如果你对一个volatile字段进行写操作,你必须知道:1、一旦你完成写入,任何访问这个字段的线程将
会得到最新的值。2、在你写入前,会保证所有之前发生的事已经发生,并且任何更新过的数据值也是可见的,因为内存屏障会把之前的写入值都刷新到缓存。

让一个volatile的integer自增(i++),其实要分成3步:
1)读取volatile变量值到local;
2)增加变量的值;
3)把local的值写回,让其它的线程可见。加写屏障
从Load到store到内存屏障,一共4步,其中最后一步jvm让这个最新的变量的值在所有线程可见,也就是最后一步让所有的CPU内核都获得了最新的值,但中间的几步(从Load到Store)是不安全的,中间如果其他的CPU修改了值将会丢失。所以volatile不能保证i++操作的原子性

并发三特性总结

特性 volatile synchronized Lock Atomic
原子性 无法保障 可以保障 可以保障 可以保障
可见性 可以保障 可以保障 可以保障 可以保障
有序性 可以保障 可以保障 可以保障 无法保障

volatile和synchronized的区别

1.volatile本质是在告诉jvm变量需要从主存中读取; synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。

2.volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的.

3.volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性

4.volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。

5.volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值